---
title: "Сторінки публічного профілю"
description: "Публічний профіль /{username} з NFT, блогом, Player, Games, Gallery і унікальною статистикою відвідувань personal_page_view (24 год/7 днів за роллю)"
locale: "uk"
---
# Сторінки публічного профілю

> **Info**
> Використовуйте вкладки **Founder** / **Developer** на бічній панелі документації, щоб відфільтрувати цю сторінку. Персональні файлові медіа, mood audio та доступність peer-game — окремі маршрути під тим самим username; див. [Ring File Cabinet](/docs/features/file-cabinet.md) і [Peer Games](/docs/features/peer-games.md). Телеметрія відвідувань приєднується до загальної аналітики Ring — див. [Monitoring & Analytics](/docs/deployment/monitoring.md).

Кожен користувач із зарезервованим username може відкрити **публічний профіль** на `/{username}` (за потреби з префіксом locale). Сторінка рендериться сервером App Router із динамічними SEO-метаданими. Пов’язані публічні поверхні:

| URL | Призначення |
|-----|---------|
| `/{username}` | Заголовок профілю, bio, NFT-лістинги, blog/staking, коли ввімкнено; записує `personal_page_view` для не-власників |
| `/{username}/img` | Lightbox галереї File Cabinet (`visibility=public`) |
| `/{username}/player` | Публічний mood player (оболонка DaVinci + плейлисти у правій рейці) |
| `/{username}/games` | Публічна доступність peer-game («Play with me») |
| `/profile/songs` | **Приватне** керування mood-player |
| `/profile/games` | **Приватне** керування Member для ввімкнених game slug |

Власники бачать віджет **статистики відвідувань** (унікальні відвідувачі за 24 год / 7 днів із розподілом за роллю відвідувача). Власні перегляди пропускаються, тому оновлення власної сторінки не завищує унікальні значення.

### For founders

## Чому це важливо для вашого клону

Публічний профіль — це **обличчя довіри** учасника: хто він, що продає/виставляє, які медіа обирає показати і (через Peer Games) які безкоштовні мініігри приймає. Видимість головної сторінки сьогодні бінарна — приватні профілі повертають 404. Статистика унікальних відвідувань допомагає учасникам бачити, чи приваблює їхня сторінка гостей, subscriber або member, не враховуючи самих себе.

  
- **[Резервування username](/docs/features/username-reservation.md)** — Спершу заявіть `@handle` — публічні маршрути розв’язуються через getUserByUsername.

  
- **[Галерея File Cabinet](/docs/features/file-cabinet.md)** — Власний менеджер member+ на `/file-cabinet`; публічні елементи — на `/{username}/img`.

  
- **[Peer Games](/docs/features/peer-games.md)** — Учасники вмикають slug на /profile/games; відвідувачі кидають виклик із /{username}/games.

  
- **[Monitoring & Analytics](/docs/deployment/monitoring.md)** — Події personal_page_view потрапляють у analytics_events; адміністратори бачать personalPages на /admin/analytics.

### Чекліст оператора

- Підтвердьте заявлений username і видимість «Personal page» у налаштуваннях профілю.
- Перевірте `/{username}` як анонімний відвідувач — віджет власника має показати унікальне відвідування після звернення не-власника.
- Підтвердьте, що перезавантаження власником **не** збільшує унікальні лічильники.
- Керування власною галереєю залишається на `/profile/gallery` (**member+**).
- CRUD приватних плейлистів залишається на `/profile/songs`.

  Окремі перемикачі публічності для кожного поля контакту (email, phone, social) ще не випущені — вважайте поточним гейтом перемикач personal-page.

### For developers

## Карта маршрутів

| Шлях App | Нотатки |
|----------|--------|
| `app/[locale]/[username]/page.tsx` | Головний профіль; `getUserByUsername`; `notFound()` якщо відсутній / приватний; пропускає `recordPersonalPageView`, коли `isOwner` |
| `app/[locale]/[username]/img/page.tsx` | `listPublicGalleryByOwner` + `PublicProfileImgGallery` |
| `app/[locale]/[username]/player/page.tsx` | `PublicPlayerShell` + сервіс mood-player |
| `app/[locale]/[username]/games/page.tsx` | Публічні ввімкнені slug + Play-with-me |
| `app/[locale]/(protected)/profile/songs/page.tsx` | Автентифіковане керування mood-player |
| `app/[locale]/(protected)/profile/games/page.tsx` | Доступність game для автентифікованого Member |

Константи: `ROUTES.PUBLIC_PROFILE_IMG`, `ROUTES.PUBLIC_PROFILE_PLAYER`, `ROUTES.PUBLIC_PROFILE_GAMES`, `ROUTES.PROFILE_SONGS`, `ROUTES.PROFILE_GAMES`, `ROUTES.PROFILE_GALLERY`.

### Аналітика відвідувань personal page (випущено)

| Питання | Шлях |
|---------|------|
| Тип події | `personal_page_view` → `analytics_events` через `insertAnalyticsEventBatch` |
| Реєстратор | `features/analytics/lib/personal-page-analytics.ts` → `recordPersonalPageView` |
| Пропуск власника | Сторінка: `if (isOwner) return` перед записом; recorder: пропуск коли `visitorUserId === profileUserId` |
| SSOT типів | `features/analytics/types/personal-page.ts` (`PersonalPageVisitStats`, рольові buckets) |
| Action віджета власника | `getPersonalPageViewStats` у `features/auth/services/personal-page-stats.ts` (власник або platform admin) |
| UI віджета | `features/auth/components/personal-page-widget.tsx` |
| Зведення для адміна | `getPersonalPagePlatformStats` → `PlatformAnalyticsSummary.personalPages` на `/admin/analytics` |
| Приєднання engagement | `analytics-db.ts` включає `personal_page_view` разом із `docs_page_view` / `page_view` / `app_load` у агрегатах pageViews |
| Kill switch | `ANALYTICS_DISABLE_STORAGE=true` — recorder нічого не робить |

Форма статистики: `unique24h` / `unique7d`, `visits24h` / `visits7d`, `byRole24h` / `byRole7d` (унікальні + відвідування за роллю). Для ідентичності відвідувача надається перевага user id, потім session key, потім anon IP.

### Пошук identity

`features/auth/services/get-user-by-username.ts` — кешований через `cache()` `queryDocs` у `users` з регістронезалежним username.

### Що є на головному профілі (перевірена поверхня)

- Avatar (`photoURL`), ім’я, `@username`, bio
- Кнопка повідомлення для автентифікованих відвідувачів (не для себе)
- Значок верифікації Telegram, коли підтверджено
- NFT-лістинги через public GET `/api/nft-market/listings?username=…`
- Розділи Blog / staking, коли це дозволяють product flags і дані
- Посилання в header/nav на **Player**, **Games** і **Gallery**
- Віджет статистики відвідувань власника (коли показано owner chrome)

### Видимість

Користувачі керують публічною видимістю через процес username / personal-page. **Public** → сторінка рендериться; **Private** → маршрут повертає **404**.

### Пов’язані API (суміжні з профілем)

| Endpoint | Призначення |
|----------|---------|
| `GET /api/auth/check-username` | Доступність |
| `GET /api/nft-market/listings?username=` | Публічні лістинги |
| `POST /api/auth/telegram/callback` | Callback верифікації Telegram |

Дані галереї File Cabinet — це **не** окремий публічний REST-список: сторінка img читає їх через `listPublicGalleryByOwner`. Доступність peer-game використовує `user_peer_games` (міграція `043_peer_games.sql`).

## Пов’язана документація

- [features/profile-account](/docs/features/profile-account.md) — Той самий процес: автентифіковані Professional-віджети /profile (Organization, tags, My CV) формують публічне обличчя довіри.

- [features/file-cabinet](/docs/features/file-cabinet.md) — Наступний крок: /file-cabinet із гейтом member + упорядкування галереї; public /img для visibility=public.

- [deployment/monitoring](/docs/deployment/monitoring.md) — Залежність: personal_page_view приєднує first-party analytics_events і personalPages адміністратора.

- [features/peer-games](/docs/features/peer-games.md) — Той самий процес: доступність public /{username}/games і керування Member на /profile/games.

- [features/username-reservation](/docs/features/username-reservation.md) — Передумова: зарезервований username потрібен перед розв’язанням публічних маршрутів /{username}.

- [features/member-blog](/docs/features/member-blog.md) — Той самий процес: секція blog у профілі, коли membership активний.

- [features/nft-market](/docs/features/nft-market.md) — Див. також: публічна NFT-сітка ProfileListings на сторінці профілю.

- [integrations/ring-cdn](/docs/integrations/ring-cdn.md) — Залежність: зображення публічної галереї використовують URL CDN /files/{uuid}.
