# DigiDala — Canonical Project Context

> **Purpose:** This is the compact handoff document to read first when resuming
> DigiDala work. It is intentionally more stable and less chronological than
> `PROJECT_STATE.md`.
>
> **Rule:** Never treat model memory as authoritative when this file, the repo,
> a release artifact, or a supplied test log can answer the question.
>
> Historical sections below may use the word “current” relative to their own
> checkpoint date. Those statements are historical snapshots, not the present
> project state. The present checkpoint is recorded in `docs/PROJECT_STATE.md`.

---

## 1. Product identity and core idea

**Project:** DigiDala.

Original working name: SandMandala. The public project name was changed from PixDala to DigiDala.

DigiDala is not fundamentally a “pixel-selling app”. The intended product is a
platform of collective digital art objects that people create together and,
after completion, turn into an event, memory, or meaningful result.

Core emotional/product loop:

```text
creation → growing participation → trembling → completion
→ ritual destruction → archive → legacy / next object
```

The strongest conceptual principle established at project start:

> People create something together so that they can eventually let it go
> beautifully.

The user participates in a concrete cell/segment, leaving a name and message.
A finite number of cells creates scarcity and a natural ending. Near completion,
the object enters “trembling”: visual glow + heartbeat. After completion, a ritual
destruction makes the finished object historical rather than permanent.

---

## 2. Product directions established early

These are **future product directions**, not current MVP requirements.

Potential DigiDala modes:

- Public — paid cell participation;
- Charity — cell participation linked to a fundraising goal;
- Event — collective participation for an event;
- Community — free/random participation;
- Sponsor — paid branded areas;
- Challenge — team competition;
- Memorial — messages/memory;
- Creator — an author creates their own DigiDala.

Important future ideas:

- charity campaigns where cell completion visually advances a target;
- “Last Pixel” / Destroyer role;
- dynamic or premium final cells;
- numbered historical DigiDala objects;
- immutable archive after destruction;
- participant “My DigiDala” history;
- post-destruction participant legacy/trace;
- teams and social neighbour relationships;
- streamer/event scenarios;
- alternative geometries beyond squares.

Architecture should allow these later, but **do not add these features to the MVP
prematurely**.

---

## 3. Original MVP concept

The original technical brief defined:

- Telegram Mini App;
- Telegram Stars payments;
- image split into finite cells;
- cell click → name/message modal;
- purchased cell reveals its image fragment;
- purchase sound;
- trembling near completion;
- ritual destruction;
- archive/new cycle;
- backend with Node.js + Express/Fastify;
- SQLite initially;
- Telegram `initData` validation on the server;
- server-authoritative ownership;
- audit/moderation groundwork.

Original domain entities:

```text
User
Cell
Mandala
```

Lifecycle:

```text
draft → active → trembling → complete → destroying → archived
```

A 2×2 development test used the third acquired cell as the trembling trigger and
the fourth as completion. The real current Mini App was later expanded to 12 cells
(4×3).

The original project principle was that the UI must not be the source of truth;
the domain/application layer owns business state.

---

## 4. Current MVP scope

The current engineering priority is **P0 / core**.

The current tagged engineering checkpoint is `v0.4.0-alpha.50.9.2`. The test Mini App still contains a free Sandbox, while the Support Mandala exercises the internal `pix` economy. Telegram identity remains server-authoritative, the last participant is determined by acquisition time, and completed cyclic Mandalas reset into a new cycle. Campaign Mandalas archive after destruction rather than resetting. The first campaign is Daughter (`daughter`), and its archive now preserves participant-level traces with deterministic participant colors, whole-trace hover highlighting, message icons and Telegram archive deep links.

Already implemented and validated to varying degrees:

- framework-independent domain core;
- SQLite persistence;
- backend/API;
- server-authoritative cell occupation;
- Telegram Mini App integration foundation;
- Telegram initData server validation;
- test bot;
- test deployment and rollback infrastructure;
- backend/integration/API tests;
- client/server state synchronization;
- ritual lifecycle groundwork;
- archive transition groundwork.

The core remains authoritative and the Sandbox remains free. The project-support Stars rail is implemented as a separate external funding path; it does not create or mutate the internal `pix` balance model. The internal `pix` economy is implemented for the Support Mandala. Pix cell debits are linked to cycle-scoped occupation events, while legacy ledger rows from the test-era schema remain untouched during migration. Alpha.49.4 verified the insufficient-Pix modal flow on Desktop and Android: the modal remains open, the existing error is shown inside it, and the cell remains unoccupied.

---


## 4.7. Current Telegram navigation and Main Mini App configuration

The current managed bot is `@PixDala_bot`. The stable Mini App entry URL remains:

```text
https://im-test.bktis.ru/apps/miniapp/
```

Private-chat launch uses Telegram `web_app`. Group navigation cannot use `web_app` inline buttons, so it uses Main Mini App deep links:

```text
?startapp
?startapp=support
?startapp=creative
```

The project-support action intentionally uses the ordinary bot deep link `?start=support` and then continues through the existing private Stars flow.

The Main Mini App must be configured for `@PixDala_bot` in BotFather to the stable Mini App URL. This configuration is external to the repository and is required for group `startapp` links to work. The requirement was verified on 2026-09-14 after diagnosing Android fallback-to-Sandbox and Desktop `BOT_INVALID`; no application-code change was required for the fix.

The Mini App resolves the initial Mandala slug in this order:

```text
mandala
→ startapp
→ tgWebAppStartParam
→ Telegram.WebApp.initDataUnsafe.start_param
→ sandbox
```

## 4.8. Alpha.50.6 / 50.6.1 — bot administration and Competitive Mandalas

Alpha.50.6 was the local candidate at that historical checkpoint, after the verified Alpha.50.5.9 checkpoint.

The existing `@PixDala_bot` gains a private-chat-only administration layer. Administrative access is keyed by Telegram numeric user ID and role (`content_admin` or `superadmin`). Initial superadmins are supplied outside Git through `TELEGRAM_SUPERADMIN_IDS`. Admin commands are deliberately absent from the public help and command menu.

The bot can manage two persistent pieces of public/private copy (`welcome_message` and `about_message`) and can create queued Competitive Mandalas from two uploaded PNG files, a Pix price per cell and a description. `/competitive_edit <slug>` can edit the price and description; price changes are locked after the first cell occupation.

Competitive Mandala model:

```text
mode = competitive
20×20 = 400 cells
200 cells per side
10 Pix / cell
one cell per user / cycle
winner = first side with 200 occupied cells
```

No team entities are introduced. The user chooses the side/image through the cell they occupy. Each side uses its own PNG asset; each source file is exactly 1024×2048 RGB/RGBA 8-bit, and the two files form a 2048×2048 square when placed side-by-side.

Competitive campaigns use the existing campaign archive/trace foundation. `winner_side` is persisted, the winning artwork remains color in the archive and the losing artwork is grayscale. Queued campaigns are activated automatically after the previous competitive campaign is archived.

Campaign artwork is stored outside release directories under `PIXDALA_CAMPAIGN_ASSETS_DIR` (default `/opt/pixdala/data/campaign-assets`).


## 4.6. Alpha.37 synchronization direction

The first multi-client synchronization foundation uses a monotonic server-side
Mandala revision and lightweight polling rather than WebSockets.

```text
SQLite mandala.revision
        ↓
GET /api/v1/mandalas/1
        ↓
Mini App compares revision
        ↓
if changed → apply authoritative snapshot
```

The Mini App polls roughly every 2 seconds while open and refreshes again when the
document becomes visible. Background synchronization updates Mandala state and cell
presentation without overwriting the user's message textarea.

The selected-cell race is handled explicitly: if another participant occupies the
cell while the user is composing, the draft remains visible but the occupation
action is disabled and the UI reports the conflict.

This is intentionally a first reliable foundation. WebSocket/SSE and event-stream
optimizations are not required at the current scale and should not be introduced
prematurely.

## 4.9. Alpha.50.9–50.9.2 — RU/EN localization and Telegram bot localization

The RU/EN localization stage is now implemented and manually verified across the Mini App and managed Telegram bot.

Mini App localization established in Alpha.50.9 includes:

- shared RU/EN locale metadata and dedicated application dictionaries;
- automatic Telegram-language selection and persisted manual locale preference;
- localized user-facing interface, dynamic states, errors and campaign presentation;
- localized campaign titles/descriptions/goals stored separately from Mandala mechanics.

Telegram bot localization established in Alpha.50.9.1 and corrected in Alpha.50.9.2 includes:

- bot-specific RU/EN dictionaries backed by a shared supported-locale registry;
- persisted per-user language preference with Telegram-language detection and English fallback;
- `/language` with immediate in-message switching;
- localized public, administration, payment/support and Competitive management flows;
- locale-aware `welcome_message` and `about_message` storage with Russian legacy fallback compatibility;
- migration `018_bot_localization_newline_fix.sql` for real line breaks in system-default welcome content.

Verified release checkpoints:

```text
v0.4.0-alpha.50.9.1  3200550  108/108 automated  deployed  manual Telegram QA passed
v0.4.0-alpha.50.9.2  75c430c  110/110 automated  deployed  manual Telegram QA passed
```

The current test release is `v0.4.0-alpha.50.9.2` at `/opt/pixdala/current`. The existing bot account, username `@PixDala_bot`, token and technical deployment identifiers remain unchanged.

## 4.8. Campaign archive and QA state

The `campaigns` model now has a verified end-to-end implementation through alpha.50.5.9.
The Daughter campaign (`daughter`, Mandala #5, 10×10 / 100 cells, 370 Pix per cell)
uses campaign artwork, is excluded from the regular cyclic catalog and becomes an
immutable archive after destruction rather than starting a new cycle.

Archive behavior established in Alpha.50.5.7–50.5.8 includes:

- participant-level trace data for occupied cells;
- deterministic participant-specific colors;
- whole-trace highlighting when a participant or trace cell is hovered;
- transparent vector message icons on archived cells that contain messages;
- Telegram archive deep links of the form `startapp=archive-<slug>`;
- direct browser campaign-archive routing preserved independently of Telegram start parameters.

The release-managed QA workflow uses `scripts/campaign-qa.mjs`. Temporary campaign
`daughter-qa` copies can be created for end-to-end testing and are removed with
`cleanup daughter-qa` after verification. The Alpha.50.5.9 manual QA completed with
no temporary QA campaigns remaining in the test database.

## 4.5. Alpha.36a bot and deployment direction

The Telegram test bot becomes part of the Git release tree:

```text
bot/test-bot.js
infra/systemd/pixdala-test-bot.service
```

The bot uses the stable Mini App entry URL:

```text
https://im-test.bktis.ru/apps/miniapp/
```

Release deployment is intended to keep web, API and bot on the same `/opt/pixdala/current`
release. The bot token remains external in `/opt/pixdala/.env`; no secret is committed.

The previous manually managed bot path `/opt/pixdala/bot-test/bot.js` is retained only
as a migration/rollback safety measure until the first release-managed bot deployment is
verified.

The next client/server foundation is multi-user state synchronization. The preferred
first implementation is versioned Mandala state plus periodic polling; background
updates must not overwrite a message currently being edited by the user. The final
occupation response remains server-authoritative and returns current Mandala state.

## 5. Repository and deployment topology

Local development repository:

```text
D:\PixDala\PixDala
```

GitHub repository:

```text
git@github.com:gbols-sup/PixDala.git
```

Server-side Git checkout used by the deployment process:

```text
/opt/pixdala/repo
```

Releases:

```text
/opt/pixdala/releases
```

Current symlink:

```text
/opt/pixdala/current
```

The obsolete historical `deploy-*` staging directories were removed during the
2026-09-03 cleanup. New deployment staging is created by the release process only.

Normal deployment scripts:

```text
scripts/deploy-test.sh
scripts/rollback-test.sh
```

`deploy-test.sh`:

1. accepts a Git tag;
2. fetches tags;
3. creates `/opt/pixdala/releases/<TAG>`;
4. extracts the exact tagged tree via `git archive`;
5. runs `npm run check`;
6. switches `current`;
7. restarts the test web service;
8. performs an HTTPS smoke check;
9. rolls back automatically if the web restart/smoke check fails.

Experimental releases were sometimes assembled manually outside this reproducible
tagged flow. Therefore:

```text
active release != main
```

is not automatically a problem during experiments.

After an experiment is accepted, required changes should be returned to source and
future releases should use the normal tagged deployment flow.

---

## 6. Development and deployment workflow
## 6.1. Preferred reproducible file preparation

When a change can be prepared safely as a complete file, prefer delivering a
ready-to-replace file or ZIP archive instead of requiring manual edits to
individual source lines.

This is an acceleration of the development workflow, not a shortcut around
engineering verification. The required sequence remains:

```text
analyze current source
→ prepare reproducible file/archive
→ replace locally in the Windows clone
→ npm.cmd run check
→ inspect diff/status
→ commit
→ push to GitHub
→ tag
→ deploy through the release process
→ Telegram/manual verification when relevant
```

For files outside the main repository, such as the Telegram test bot, use the
same prepared-file principle, but transfer the finished file explicitly (for
example with `scp`) and verify it on the VPS before restarting the service.

Ready-made files/archives must preserve the existing project structure and
must not be used to bypass tests, source review, Git history, or reproducible
deployment.

---


The established normal workflow is: 

```text
VSCode on Windows
    ↓
local Git changes
    ↓
npm.cmd run check
    ↓
git commit
    ↓
git push origin main
    ↓
GitHub
    ↓
VPS git fetch --tags
    ↓
./scripts/deploy-test.sh <tag>
    ↓
/opt/pixdala/releases/<tag>
    ↓
/opt/pixdala/current
    ↓
restart + HTTPS smoke test
```

Source files must not be edited manually on the VPS. The VPS is a deployment
environment, not the primary development environment.

Windows development environment verified on 2026-09-03:

```text
Git      2.54.0.windows.1
Node.js  22.14.0
npm      10.9.2
VSCode   1.136.0
```

GitHub SSH uses a dedicated Windows key `id_ed25519_github`; the existing
`id_ed25519` remains dedicated to VPS access.

## 6. Test infrastructure

Test services:

```text
pixdala-test-api
pixdala-test-web
```

API:

```text
http://127.0.0.1:8090
```

Public HTTPS:

```text
https://im-test.bktis.ru/
```

Mini App:

```text
https://im-test.bktis.ru/apps/miniapp/
```

Test DB:

```text
/opt/pixdala/data/pixdala-alpha-test.db
```

Web service serves:

```text
/opt/pixdala/current
```

via a local Python HTTP server on `127.0.0.1:8081`, with Nginx providing the public
HTTPS layer.

The VPS is Ubuntu 24.04, 1 vCPU, 2 GB RAM, 30 GB SSD.

Relevant installed versions observed during setup:

```text
node v24.20.0
npm 11.19.0
sqlite3 3.45.1
git 2.43.0
curl 8.5.0
```

The non-root operational user is:

```text
pixdala
```

Firewall has been configured with inbound SSH/HTTP/HTTPS and default-deny incoming.

---

## 7. Telegram bot

The current Git-managed Telegram bot source is:

```text
bot/bot.cjs
```

The active systemd unit is:

```text
infra/systemd/pixdala-bot.service
```

The bot runs from the current release at:

```text
/opt/pixdala/current/bot/bot.cjs
```

The bot launches the Mini App using:

```text
InlineKeyboardButton
+
WebAppInfo
+
web_app.url
```

The bot uses long polling.

Reference documentation:

```text
docs/TELEGRAM_TEST_BOT.md
```

---

## 8. Important source/release split

The source of truth for development is now the GitHub repository:

```text
gbols-sup/PixDala
```

The local development copy is the Windows VSCode clone. The VPS repository is used
for fetching tags and producing reproducible releases; it is not a place for manual
source editing.

Current source/release checkpoint:

```text
Code tag: v0.4.0-alpha.50.5.9
Code commit: ab31892
Documentation commit: 17f4a63
```

Current branch state after alpha.41:

```text
main == origin/main
```

The working tree may contain unrelated pre-existing modifications that are outside the verified alpha.41 release scope.

Product baseline:

```text
v0.4.0-alpha.28
```

Current technical verification release on the test VPS:

```text
v0.4.0-alpha.28-winfix
```

`v0.4.0-alpha.28-winfix` is a workflow-verification tag, not a new product
baseline. Its code comes from commit `8e94695`; the package version remains
`0.4.0-alpha.28`.

---

## 9.1. Historical verified checkpoint: alpha.39

## 9.2. Alpha.33 lifecycle verification

`v0.4.0-alpha.33` introduced and verified the server-authoritative destruction
lifecycle for the Mandala Sandbox.

Key changes:
- destruction start is authorized by the server for the actual last acquirer;
- the completed-state destroy action is no longer dependent on a browser-only
  claim about who is the last participant;
- the sandbox can reset through the server-side lifecycle;
- stale `destroying` state is recovered into an empty active sandbox;
- the obsolete “Остаться на минуту” action was removed from the intended UI;
- public cell data no longer needs to expose Telegram IDs merely to support the
  destroy authorization path.

Real Telegram verification:
- Mobile: occupation, destruction and automatic reset worked;
- Desktop: occupation, destruction and automatic reset worked.

During verification a stale Mini App entry URL/cache behavior was observed.
The test bot was therefore switched to a versioned `index.html` entry URL:

```text
https://im-test.bktis.ru/apps/miniapp/index.html?v=0.4.0-alpha.33
```

The lifecycle itself was confirmed working on both Mobile and Desktop after the
fresh entry URL was used.

Alpha.33 local verification:
- structure check passed;
- JavaScript syntax check passed;
- 10 unit tests passed;
- 14 integration tests passed;
- 6 API tests passed.


`v0.4.0-alpha.32` was the verified test release at that historical checkpoint.

Commit:

```text
b327a26 feat: complete Mandala Sandbox alpha.32
```

Tag:

```text
v0.4.0-alpha.32
```

Active release on the test VPS at that historical checkpoint:

```text
/opt/pixdala/releases/v0.4.0-alpha.32
```

Current Mini App test URL:

```text
https://im-test.bktis.ru/apps/miniapp/
```

Alpha.32 defined the Mandala Sandbox test behavior adopted at that historical checkpoint:

- payment is disabled;
- cells may be occupied in any order;
- participant name and Telegram ID are displayed from validated Telegram identity;
- manual participant-name input is removed;
- only the final acquirer may start destruction;
- final acquirer is determined by acquisition time, not cell position;
- destruction auto-resets the test Mandala to an empty active state.

The release was deployed with `scripts/deploy-test.sh`; project checks, service checks and HTTPS smoke test passed. Manual Telegram Desktop verification passed at that historical checkpoint.

---

## 9. Confirmed active release: alpha.28

`v0.4.0-alpha.28` is the current **production-like test baseline**.

It was promoted from the verified alpha.24-clean line and:

- keeps the Telegram SDK in `index.html` before the application module;
- uses client version/cache marker `0.4.0-alpha.28`;
- removes all temporary alpha.25–27 diagnostic UI;
- removes the leftover `setDiag` confirmation-flow diagnostic helper and its temporary status messages;
- keeps the inline client domain model;
- keeps server-authoritative occupation;
- keeps bootstrap/retry/timeout logic;
- keeps duplicate-confirmation protection;
- keeps server-state reconciliation.

Local check:

```text
npm run check
```

passed:

```text
9 unit tests
11 integration tests
5 API tests
```

---

## 9.3. Alpha.34 release candidate (historical)

The alpha.34 candidate at that historical checkpoint contained a presentation-only refinement
to occupied-cell UI.

Goals:
- make user/message icons comparable to the text size;
- keep each icon on the same row as its corresponding name/message;
- keep the occupied-cell information block centered inside the cell;
- prevent the block from jumping vertically when names/messages wrap to
  different numbers of lines;
- constrain the information block to the cell width consistently on Desktop
  and Mobile.

The alpha.34 candidate is intentionally limited to this UI refinement plus
documentation updates. The verified alpha.33 server lifecycle is not being
changed.

Latest local verification before release:
- structure check passed;
- JavaScript syntax check passed;
- 10 unit tests passed;
- 14 integration tests passed;
- 6 API tests passed.

Alpha.34 is not yet a tagged or deployed release at the time of this snapshot.


## 10. Android diagnostic conclusion

The Android problem investigated in alpha.25–27 was:

```text
WebApp: NO
initData: NO
user: NO
```

Alpha.26 moved the Telegram SDK into `<head>` and the problem remained.

Alpha.27 added explicit SDK loading diagnostics and produced:

```text
SDK: ERROR · URL data: NO
WebApp: NO · initData: NO (0)
user: NO · platform: — · version: —
```

The server logs showed the Mini App itself was being served successfully.

The decisive verification was a full-VPN / unrestricted-network test:

- Mini App loaded;
- `GET /api/v1/mandalas/1` succeeded;
- Android occupation POST succeeded with HTTP `201`;
- Desktop occupation also succeeded with HTTP `201`.

Conclusion:

**Telegram SDK availability in the affected Android network path was an environmental
network issue, not a demonstrated API occupation failure.**

Russian blocking/bypass behavior is **not a DigiDala product requirement**.
Do not add product complexity solely to compensate for that test environment.

---

## 11. GET timeout/retry: definitive historical answer

The earlier discussion mistakenly treated the origin of the `45s` value as unknown.

The supplied release artifact `PixDala_v0.4.0-alpha.18.zip` resolves this.

Its `CHANGELOG.md` explicitly says:

```text
Increased initial mandala GET timeout to 45 seconds for slow Telegram mobile connections.
```

The same alpha.18 entry also says:

- retry was fixed so each attempt uses a fresh `AbortController` and timeout;
- occupation POST timeout remained 15 seconds;
- confirmation waits for the shared bootstrap while initial synchronization is in progress.

Therefore:

**45 seconds was an intentional stabilization measure introduced for slow Telegram
mobile connections.**

This is stronger evidence than the current Git history because the alpha.18 release
artifact itself documents the reason.

The chronological evolution is:

```text
alpha.12
  → one lightweight retry for initial Mandala API read

alpha.17
  → occupation waits for shared bootstrap promise

alpha.18
  → GET timeout increased to 45s for slow Telegram mobile connections
  → retry corrected to use fresh AbortController + timeout per attempt
  → POST timeout kept at 15s

alpha.19
  → temporary confirmation diagnostics removed
  → alpha.18 mobile network/bootstrap stabilization retained

alpha.20
  → client-side Mandala model inlined
  → removes a runtime network request
  → mobile bootstrap/retry retained

alpha.21
  → complete domain model inlined
  → runtime HTTP dependency on packages/domain/mandala.js removed

alpha.22
  → stale diagnostic handler removed
  → production binding restored
  → inline domain model + mobile bootstrap/network fixes retained

alpha.23
  → temporary Android occupation diagnostics only

alpha.24
  → clean production-like release based on alpha.22
  → diagnostics removed
  → mobile bootstrap + network retry retained

alpha.24-clean
  → same clean baseline, cache/version marker updated
  → verified on Desktop + Android with unrestricted network

alpha.28
  → promoted the verified alpha.24-clean client baseline into `main`
  → removed leftover `setDiag` confirmation-flow diagnostics
  → synchronized client version/cache marker to alpha.28
  → structure checker accepts versioned `app.js` URLs
  → automated and manual verification passed
```

Thus the correct current position is:

**Do not remove the 45s timeout merely because its number looked arbitrary. Its
documented purpose is slow Telegram mobile connections.**

However, the *current value* may still be subject to future empirical review.
The next engineering question is whether 45s is still the right operational value
for the target environment, not whether it was introduced for a real reason.

---

## 12. Current client network behavior

The active `alpha.28` GET logic is approximately:

```text
attempt 1
  GET /api/v1/mandalas/1
  timeout 45s
  on ordinary error → wait 350ms → attempt 2

attempt 2
  fresh AbortController
  timeout 45s

failure after retries
  apiState = offline
```

`AbortError` does not trigger the second attempt.

Occupation POST has its own:

```text
15s timeout
```

The current implementation also performs:

- Telegram initData presence check;
- server-authoritative POST;
- server response parsing;
- error mapping;
- server state reconciliation after writes.

---

## 13. Release history that matters for future reasoning

### alpha.12
Introduced a lightweight initial GET retry, post-write server verification,
and other mobile/ritual stability changes.

### alpha.13
Returned confirmation to the known-working direct `onclick` mechanism.

### alpha.14
Removed the form wrapper while keeping direct `onclick`.

### alpha.15
Removed early focus/audio initialization and added mobile hit-testing diagnostics.

### alpha.16
Added a minimal diagnostic button and an immediate “Нажато” marker.

### alpha.17
Solved a race where the user could act before initial API synchronization completed:
confirmation waits for shared bootstrap.

### alpha.18
Mobile network stabilization:
45s initial GET timeout, corrected retry, fresh AbortController/timeout,
15s POST timeout, shared bootstrap waiting.

### alpha.19
Removed temporary confirmation diagnostics.

### alpha.20
Inlined the client domain model and added a lightweight boot elapsed-time marker.

### alpha.21
Completed domain-model inlining and removed runtime network dependency on
`packages/domain/mandala.js`.

### alpha.22
Cleaned the stale Android diagnostic handler; restored production confirmation
binding. This is the important functional baseline.

### alpha.23
Temporary Android diagnostics. Invalid as a production baseline because of a
diagnostic binding error.

### alpha.24
Clean production-like release based on alpha.22.

### alpha.24-clean
Current verified production-like test baseline.

### alpha.25–27
Temporary diagnostics for Android Telegram SDK/initData investigation. Not baseline.

---

## 14. Domain/client architecture facts

Domain core currently models:

```text
User
Cell
Mandala
```

Mandala state machine:

```text
draft
active
trembling
complete
destroying
archived
```

The domain layer owns business state and lifecycle rules.

The UI is not the source of truth.

The backend persists/authoritatively applies server state. Repositories translate
between persistence and domain/application logic.

The current Mini App client contains an inlined copy of the client domain model to
avoid a runtime request for:

```text
/packages/domain/mandala.js
```

This was a deliberate reliability improvement after mobile/cache/network problems.

---

## 15. Important frontend reliability history

Several mechanisms were introduced because of real observed Telegram/mobile behavior,
especially around event handling and stale assets:

- versioned `app.js` cache busting;
- matching version marker in HTML and JS;
- direct `onclick` handling;
- temporary touch/pointer diagnostics;
- duplicate/in-flight protection;
- shared bootstrap promise;
- initial API retry;
- explicit timeout;
- fresh AbortController per retry;
- server-state verification after writes;
- server-state reconciliation;
- inline domain model to remove runtime module fetch.

Some of these may later be simplified, but every removal must be tested individually.

---

## 16. Current audit strategy

Do not make a mass “cleanup”.

Audit one mechanism at a time:

```text
1. GET timeout (45s)
2. GET retry
3. fresh AbortController per retry
4. POST timeout (15s)
5. bootstrapPromise / ensureBootstrap
6. waiting for bootstrap before confirmation
7. server-state reconciliation
8. inline client domain model
```

For each mechanism answer:

```text
Why was it introduced?
What real failure did it address?
Is that failure still relevant?
Can the mechanism be simplified?
What test demonstrates the change is safe?
```

Do not change multiple mechanisms in the same experimental release unless the
relationship between them is itself what is being tested.

---

## 17. Testing discipline

For every meaningful change:

```text
explain
→ make reproducible change
→ run automated checks
→ run local tests
→ test in Telegram when relevant
→ inspect logs when relevant
→ commit
→ document architectural decisions
```

The owner is a strong general technical/system-administration user but not a
professional software developer, so procedures should remain explicit and
reproducible.

When logs matter, always provide the exact command to inspect them.

When uploading release files from Windows, use explicit `scp` commands rather than
assuming files are already on the server. For source development, do not upload
individual edited source files to the VPS; use GitHub and the tagged deployment flow.

---

## 18. Current documentation strategy

`docs/PROJECT_STATE.md` remains the chronological operational journal.

This file, `docs/PROJECT_CONTEXT.md`, is the **canonical compact handoff/context**.

Purpose separation:

```text
PROJECT_CONTEXT.md
  = stable facts, architecture, decisions, current baseline, constraints

PROJECT_STATE.md
  = chronological work log, experiments, current session state

ROADMAP.md
  = project direction and ordering

ADR
  = architecture decisions and constraints

CHANGELOG.md
  = release-specific history
```

When resuming a session:

1. read `PROJECT_CONTEXT.md`;
2. read the current tail of `PROJECT_STATE.md`;
3. review `docs/ROADMAP.md` before starting a substantial stage;
4. inspect the actual active release/source if the task is code-related;
5. do not infer missing facts from model memory when artifacts can establish them.

---

## 19. Source-of-truth precedence

When information conflicts, use this order:

```text
1. Actual current server state / actual release files
2. Git repository and committed docs
3. Supplied release artifacts / test logs
4. PROJECT_STATE.md
5. PROJECT_CONTEXT.md
6. Conversation transcript
7. Model memory / inference
```

A lower source can explain why something happened, but a higher source wins for
the actual current state.

When the reason for a decision exists only in an old transcript or release artifact,
record that provenance explicitly rather than silently converting it into a Git fact.

---

## 20. Current task at the moment of this context snapshot

The Android blocker is considered resolved for the normal/unrestricted target path.

The verified `alpha.28` baseline remains the product baseline. The technical
`alpha.28-winfix` release verified the new GitHub-based deployment workflow without
changing product behavior.

The current engineering task remains the controlled P0 work that was in progress
before the workflow migration: continue the historical client reliability audit
without breaking the verified alpha.28 baseline.

The first audit target is GET timeout/retry. The historical `45s` reason is known:
slow Telegram mobile connections. Do not remove it by intuition; inspect and test
one mechanism at a time.

The next new product/code task (after this documentation checkpoint) may be the
temporary test-only Mandala reset, but it must be implemented locally in VSCode,
validated, committed to GitHub, tagged, and deployed through the reproducible release
process.

Before starting the next substantial development stage, review `ROADMAP.md`,
`PROJECT_STATE.md`, and this context.

### Current checkpoint update — alpha.32

Alpha.32 was the verified checkpoint at that historical stage.

The alpha.30 Telegram auth fix remains part of the active source, while alpha.32 adds the Mandala Sandbox UI/identity/lifecycle behavior described above.

The GitHub-backed workflow and tagged deployment mechanism remain authoritative; source files must not be edited manually on the VPS.

## 21. Key “do not forget” constraints

- DigiDala is more than a pixel-sales app; participation/event/archive is the core.
- Keep MVP small despite broad future product ideas.
- Backend/domain are authoritative.
- Telegram `initData` must be validated server-side.
- Do not treat Russian blocking as a product requirement.
- Active release and `main` may differ during experiments.
- alpha.22 is the important clean functional baseline before diagnostics.
- alpha.23 is not a valid baseline.
- alpha.24-clean was the verified production-like baseline used for the alpha.28 promotion.
- alpha.28 is the historical verified production-like test baseline and tagged source release.
- alpha.32 was the verified Mandala Sandbox checkpoint at that historical stage.
- `45s` exists intentionally for slow Telegram mobile connections.
- Never infer experimental release history from `main` alone.
- `docs/ROADMAP.md` is the source of truth for project direction and ordering.
- `AI_HANDOFF.md` is the mandatory assistant working contract for cross-chat continuation.
- Review `ROADMAP.md` before each substantial development stage.
- Do not perform broad cleanup in one step.
- Preserve reproducibility and document why a mechanism exists before removing it.
- `setDiag` and its temporary confirmation messages were removed in alpha.28 and verified
  without functional regressions.
- Source development uses Windows VSCode + GitHub; VPS source files are not edited manually.
- Ready-made files/ZIP archives are preferred when a change can be prepared safely as a complete reproducible file.
- Prepared files accelerate the workflow but never replace source review, automated checks, Git history, or tagged deployment.
- `v0.4.0-alpha.28-winfix` is a technical workflow-verification tag, not a product release.
- `v0.4.0-alpha.32` was the last verified tagged checkpoint before alpha.33/alpha.34.


## 2026-09-06 — alpha.36.1 bot migration fix

The release-managed test bot is stored in Git as `bot/test-bot.cjs` because the
repository uses ESM via `"type": "module"` while the bot remains a small CommonJS
service. The stable Mini App entry URL is `https://im-test.bktis.ru/apps/miniapp/`.
The bot systemd unit points at `/opt/pixdala/current/bot/test-bot.cjs`.

The deployment script now validates and restarts the bot together with web/API and
can restore the preserved legacy bot unit during rollback when the previous release
predates the Git-managed bot.

---

## Historical candidate — alpha.38

Alpha.38 was the controlled refinement after the fully verified alpha.37 synchronization
foundation. It does not change the polling architecture. It fixes participant accounting,
cell-acquisition audio activation, completion overlay stacking, and client-side propagation
of the server-authoritative destruction start.

For destruction propagation, the server remains authoritative: a destroyer starts the
`destroying` state, clients observe it through the existing revision polling, and non-destroyer
clients animate locally without calling the finish endpoint. Only the destroyer completes the
server-side reset.

The stable Mini App entry URL remains:

```text
https://im-test.bktis.ru/apps/miniapp/
```

Alpha.38 was a local release candidate at that historical checkpoint.

---

## Historical verified checkpoint — alpha.39

`v0.4.0-alpha.39` was deployed to the test VPS and manually verified on Telegram Mobile and Desktop with multiple users.

Release identity:

```text
Commit:
1cb24ac

Tag:
v0.4.0-alpha.39
```

Automated verification:

```text
Structure: OK
JavaScript syntax: OK
Unit: 10/10
Integration: 17/17
API: 8/8
Total: 35/35
```

Deployment:

```text
/opt/pixdala/releases/v0.4.0-alpha.39
```

The release was deployed through `scripts/deploy-test.sh v0.4.0-alpha.39`.

Manual verification passed: Desktop completion overlay stacking; dedicated completion message for a different Telegram user; remote destruction particle animation; reset synchronization; and cross-viewer occupation audio. The final-participant completion flow was also verified.

The server remains authoritative: the last participant initiates destruction, other already-open clients observe `destroying` through revision polling and animate locally, and only the destroyer completes the server-side reset.

The stable Mini App entry URL remains:

```text
https://im-test.bktis.ru/apps/miniapp/
```

Source development remains Windows VSCode → GitHub → tagged deployment. The VPS is not a manual development workspace.

---

## Historical superseded candidate — alpha.40

Alpha.40 was based on the verified alpha.39 release and was successfully committed, tagged and deployed, but its manual acceptance failed.

The candidate changed the text of `stageOverlay`, while the visible final completion card is the separate `celebrate` overlay in `apps/miniapp/index.html`. The deployed `celebrate` card therefore still displayed the previous final-participant copy.

Alpha.40 was not rewritten or retagged. It remains an immutable historical release checkpoint and was superseded by alpha.41.

---

## Current verified checkpoint — alpha.41

`v0.4.0-alpha.41` was the verified test release at that historical checkpoint.

Release identity:

```text
Commit:
0da0b38

Tag:
v0.4.0-alpha.41
```

The final-participant completion card was corrected in the actual `celebrate` overlay.

Exact verified UI copy:

```text
Мандала завершена!

Пора отпустить созданное...
```

The existing action button remains:

```text
Развеять мандалу
```

No server lifecycle, synchronization, destruction, audio, or other unrelated behavior was intentionally changed in alpha.41.

Automated verification:

```text
Structure: OK
JavaScript syntax: OK
Unit: 10/10
Integration: 17/17
API: 8/8
Total: 35/35
```

Deployment:

```text
/opt/pixdala/releases/v0.4.0-alpha.41
```

The release was deployed through `scripts/deploy-test.sh v0.4.0-alpha.41`.

Manual verification passed on Telegram Mobile and Telegram Desktop. The exact final-participant completion copy and the existing destruction button were verified on both platforms.

The server remains authoritative: the last participant initiates destruction, other already-open clients observe `destroying` through revision polling and animate locally, and only the destroyer completes the server-side reset.

The stable Mini App entry URL remains:

```text
https://im-test.bktis.ru/apps/miniapp/
```

Alpha.41 was the engineering checkpoint at that historical point in the journal.

Release identity:

```text
Commit:
f355f62d2b9116648a44bf20428d829af7035b0a

Tag:
v0.4.0-alpha.38
```

Automated verification:

```text
Structure: OK
JavaScript syntax: OK
Unit: 10/10
Integration: 17/17
API: 8/8
Total: 35/35
```

Deployment:

```text
/opt/pixdala/releases/v0.4.0-alpha.38
```

The release was deployed through `scripts/deploy-test.sh`.

Verified manually: unique Telegram participant counting works; occupation audio works at every filling stage; already-open viewers also hear another participant's occupation sound; Mobile did not show completion-overlay overlap.

Not fully verified / open: Desktop participant name/message plates still cover the completion information; non-destroyer viewers do not currently show the destruction particle animation after the server enters `destroying`; non-destroyer viewers need a distinct completion message. The final participant's existing completion text and `развеять мандалу` button remain unchanged.

Required non-destroyer completion copy:

```text
Внимание! Участник такой-то завершил мандалу и готовится её развеять.
Давайте посмотрим на это...
```

The server remains authoritative for lifecycle state and reset. Only the destroyer completes the server-side reset. Alpha.38's failure is therefore a client-side propagation/rendering issue, not a reason to weaken server authority.

The stable Mini App entry URL remains:

```text
https://im-test.bktis.ru/apps/miniapp/
```

Source development remains Windows VSCode → GitHub → tagged deployment. The VPS is not a manual development workspace.

---

## Historical verified checkpoint — alpha.37

`v0.4.0-alpha.37` was the verified test release at that historical checkpoint.

Release identity:

```text
Commit:
f3b046af268f4afeecc9374bc97215ba14a32b4f

Tag:
v0.4.0-alpha.37
```

Alpha.37 adds the first verified multi-user Mandala synchronization foundation:

- server-side monotonic Mandala `revision`;
- revision changes when shared Mandala state changes;
- Mini App polling for state updates;
- refresh when the page becomes visible again;
- background synchronization does not overwrite an actively edited message;
- client reconciliation from the server snapshot;
- protection against the race where another participant acquires the cell
  being edited;
- stable Mini App entry URL:
  `https://im-test.bktis.ru/apps/miniapp/`.

Verification status:

```text
Local automated checks: 32/32 passed
Deployment: successful
Telegram Mobile: passed
Telegram Desktop: passed
Multi-user synchronization: passed
```

The active test release is:

```text
/opt/pixdala/releases/v0.4.0-alpha.37
```

The release was deployed through `scripts/deploy-test.sh`. The GitHub-backed,
tagged release workflow remains authoritative; source files must not be edited
manually on the VPS.

Alpha.37 was the engineering checkpoint at that historical stage.
The next substantial work must be selected from `docs/ROADMAP.md`, rather than
invented from the release history alone.
---

## 2026-09-08 — Main Telegram bot naming migration preparation

The Telegram bot is being promoted from the former test-bot naming to the main
project naming while it continues to open the current test Mini App.

Current Git-managed bot files:

```text
bot/bot.cjs
infra/systemd/pixdala-bot.service
```

Current Mini App entry URL remains:

```text
https://im-test.bktis.ru/apps/miniapp/
```

The deployment script now validates and installs `pixdala-bot.service` and
launches `/opt/pixdala/current/bot/bot.cjs`.

The former `pixdala-test-bot.service` name is retained only for historical
rollback compatibility. It must not be started simultaneously with
`pixdala-bot.service`, because both units use the same Telegram bot token.

The token remains external to Git in `/opt/pixdala/.env` under
`TELEGRAM_BOT_TOKEN`.

This migration does not introduce Telegram Stars payment flow or other product
features.


---

## 2026-09-08 — Alpha.42 durable checkpoint

The Telegram bot has been promoted from the former test-bot naming to the main DigiDala naming.
The current Git-managed bot source and unit are:

```text
bot/bot.cjs
infra/systemd/pixdala-bot.service
```

The release-managed bot runs from `/opt/pixdala/current/bot/bot.cjs`. The former
`pixdala-test-bot.service` is retained only as a legacy rollback artifact for releases that
predate the migration and must not run simultaneously with `pixdala-bot.service`.

The current test Mini App remains `https://im-test.bktis.ru/apps/miniapp/`, but it is opened by
the main Telegram bot `@PixDala_bot`. The bot token remains external in `/opt/pixdala/.env`.

Alpha.42 was verified end-to-end after deployment, including Menu Button, `/start`, `/help`,
Mini App API synchronization and cell occupation.

The next product stage is the Telegram Stars payment foundation. The Sandbox remains free and
is not the payment test object. The planned first payment test is a minimal 1-Star transaction
that proves Telegram payment callbacks, server-side verification, Telegram-user association,
idempotency and auditable persistence before the pix ledger is introduced.


---

## 2026-09-09 — DigiDala public-name checkpoint

The public project name is now **DigiDala**. This is a branding/product-name change, not a technical rename. The Telegram bot remains `@PixDala_bot`; GitHub repository naming, `pixdala-*` services, `/opt/pixdala/...` paths, deployment scripts and other technical identifiers remain unchanged.

Alpha.43 is the first verified release carrying the new public name in the user-facing Mini App and bot texts. The stable Mini App URL remains `https://im-test.bktis.ru/apps/miniapp/`.


---

## 2026-09-09 — Alpha.44 payment-foundation checkpoint

The first Telegram Stars payment foundation is implemented and verified. The bot exposes a permanent `⭐ Поддержать проект` action with fixed support amounts of 1 / 5 / 10 / 25 / 50 / 100 Stars. Telegram uses currency `XTR`.

The architecture deliberately separates the external Stars payment rail from the future internal `pix` economy:

```text
Telegram Stars
      ↓
project-support payment record
      ↓
future P0.5b pix acquisition / ledger
```

Payment creation, pre-checkout verification and finalization are handled server-side. SQLite stores the purpose, amount, Telegram user association, payment status, timestamps and `telegram_payment_charge_id`. Duplicate completion is idempotent. Internal payment endpoints are restricted to localhost because they are called only by the release-managed bot.

Alpha.44 was deployed from the exact release tag and manually verified with a real 1-Star payment. The resulting payment was confirmed in the active database and linked to the Telegram user and charge ID.

Known limitation: abandoned/closed invoices can leave a payment intent in `pending`; reconciliation/recovery for such intents remains future hardening work.

## 2026-09-10 — Alpha.46.5 verified checkpoint

Alpha.46.5 was the verified client-lifecycle checkpoint after the multi-Mandala expansion. The server remains authoritative for Mandala lifecycle state: the final participant starts destruction and only that client completes the server-side reset. Other already-open clients observe the server's `destroying` state and animate the destruction locally.

The client reconstruction order is now compatible with the working pre-multi-Mandala behavior: a server payload is reconstructed into an `ACTIVE` domain model first, occupied cells are restored, and the local model can naturally reach `COMPLETE` before the remote destruction controller starts. The multi-Mandala identity/routing fields remain preserved.

Remote reset handling is explicitly tolerant of event ordering. If `active` arrives from the server before the observer's local particle animation finishes, the client records a pending remote reset and completes the visual reset only after the animation ends. If the animation finishes first, the client waits for the subsequent server reset.

The visible Mandala container is shared by the current view, so remote destruction now also restores its visibility and interaction state. During the intentionally invisible phase, pointer interaction is disabled to avoid clicks on invisible cells. This is a UI safety measure; it does not change server state.

Sandbox and Support are independent server-side Mandala identities and are also independent in the tested client navigation flow: destruction of one does not reset or destroy the other.

### Alpha.46.5 known UX issue — closed by alpha.46.6

The brief `Пока свободно` flash during Mandala switching was caused by the legacy free-cell presentation remaining in the renderer. Alpha.46.6 removes that presentation path. It must not be treated as evidence of shared Mandala state.


## 2026-09-11 — Alpha.46.6 verified checkpoint

Alpha.46.6 closes the small Mandala-switching transition artifact recorded after Alpha.46.5. The fix removes the legacy free-cell presentation itself rather than hiding the Mandala container during navigation. The renderer no longer generates the old `✦`, number, `Пока свободно` or `Тестовый режим` presentation; free cells consistently use the existing minimal SVG marker.

No server lifecycle, synchronization, backend/API, payment, polling, or Mandala identity/routing behavior was changed. Automated verification remained 48/48 and manual Telegram QA passed repeated Sandbox/Support switching without the previous flash.

The current open UX direction remains the separate readable participant/message information layer and historical-message presentation, especially before substantially larger Mandala grids are introduced.

## 2026-09-15 — Alpha.49.5 economic checkpoint and Alpha.49.6 follow-up

Alpha.49.5 is the verified economic checkpoint after the initial Pix ledger/payment foundation. The internal exchange direction is now **135 Stars -> 1 Pix**, stored as the configurable `stars_per_pix` setting. The purchase API accepts a desired Pix amount; the backend calculates the Stars quote. The Support Mandala remains priced at 1 Pix per cell, while Sandbox remains free. Existing Pix balances and historical payment records are not converted when the rate changes.

The verified Alpha.49.5 release was committed as `d34d37f`, tagged `v0.4.0-alpha.49.5`, deployed through the reproducible test deployment script, and manually verified on Desktop and Android. Automated verification was 62/62.

During manual testing of Alpha.49.5, a client-side false conflict was observed on cell occupation: after the current user successfully occupied a free cell, common background synchronization could display the notice that another participant had just taken the cell. The server operation itself succeeded: Pix was debited and the cell was occupied correctly. The issue is in the generic client synchronization path shared by Mandala views.

Alpha.49.6 is the targeted follow-up. The client now suppresses the concurrent-occupation notice when the newly observed owner is the current Telegram user, while preserving the notice for a genuinely different owner. No backend, Pix ledger, exchange-rate, payment, or Mandala occupation semantics are changed by this fix. Local automated verification remains 62/62; deployment and manual QA are still pending.


## 2026-09-16 — Alpha.50.2 economic model candidate

The project is moving from the provisional Alpha.49.5 exchange model of **135 Stars
to 1 Pix** to the agreed current rule **1 Star = 1 Pix**. Pix remains a reusable
internal balance that users can purchase in advance and spend across paid Mandalas.

Each paid Mandala continues to define its own integer `cell_price_pix`. The current
planned prices are:

- Мандала поддержки: **95 Pix per cell**;
- Daughter fundraising Mandala: **370 Pix per cell** when it is implemented.

The Pix purchase API remains server-authoritative: the client selects a Pix amount,
the backend derives the Telegram Stars amount, creates the invoice, and credits the
Pix through the existing payment/ledger flow after successful finalization.

The current Pix purchase packages are **1 / 50 / 100 / 500 / 1000 / 2000 Pix**.
Existing Pix ledger balances are preserved when this model is introduced; no
historical balance conversion is planned for the current test phase.

Alpha.50.2 is a prepared local candidate, not yet a committed, tagged, deployed or
manually verified checkpoint.


## 4.9. Competitive-only change isolation and QA workflow

Competitive Mandala changes must remain isolated from existing Mandala types. New competitive behavior must be selected explicitly by the competitive campaign mode; Sandbox, Small Creative, Large Creative, Support, Special/Daughter and their archive flows must retain their existing behavior. Regression coverage is required for shared navigation, catalog responses, cell pricing and ordinary rendering when competitive campaigns are created or edited.

Functional Telegram/Mini App QA is performed only after the exact release tag has been deployed to the VPS. Local work is limited to code review and automated/technical checks such as `npm.cmd run check` and `git diff --check`; local browser/Telegram behavior is not treated as the functional acceptance test.
