Skip to content

PWA / Mobile Specification — DAARION.city

Version: 1.0.0

0. PURPOSE

Зробити app.daarion.space Progressive Web App (PWA): - Installable — можна додати на домашній екран як додаток - Offline shell — базові сторінки працюють без мережі - Mobile-first — оптимізовано для мобільних пристроїв - Foundation for push — підготовка до push-нотифікацій


1. GOALS

1.1. Installable

  • Користувач може "Add to Home Screen" на iOS/Android/Desktop
  • Відкривається в standalone режимі (без browser UI)
  • Власна іконка та splash screen

1.2. Offline Shell

  • Головна сторінка / працює з кешу
  • Список кімнат /city працює з кешу
  • Сторінки кімнат /city/[slug] — кешований shell + повідомлення "ви офлайн"
  • Matrix чат — показує offline-стан, не намагається емулювати

1.3. Performance

  • Швидке завантаження через кешування статичних ресурсів
  • App shell architecture

2. MANIFEST.JSON

Файл: public/manifest.json

{
  "name": "DAARION.city",
  "short_name": "DAARION",
  "description": "Децентралізована платформа для мікро-спільнот з AI-агентами",
  "start_url": "/",
  "scope": "/",
  "display": "standalone",
  "orientation": "portrait-primary",
  "theme_color": "#0c4a6e",
  "background_color": "#0f172a",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any maskable"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ],
  "categories": ["social", "productivity"],
  "lang": "uk"
}

3. ICONS

Директорія: public/icons/

File Size Purpose
icon-192x192.png 192×192 Android, Chrome
icon-512x512.png 512×512 Splash screen
apple-touch-icon.png 180×180 iOS
favicon.ico 32×32 Browser tab

Дизайн: DAARION логотип (sparkles/зірка) на темному фоні (#0f172a)


4. SERVICE WORKER

Файл: public/sw.js

4.1. Cache Strategy

┌─────────────────────────────────────────────────────────────┐
│                    REQUEST FLOW                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Static Assets (/_next/static/*, fonts, images)             │
│  └── Cache First → Return cached → Update in background     │
│                                                             │
│  HTML Pages (/, /city, /city/*)                             │
│  └── Network First → Fallback to cache → Offline page       │
│                                                             │
│  API Requests (/api/*)                                      │
│  └── Network Only → No caching                              │
│                                                             │
│  Matrix/WebSocket                                           │
│  └── Network Only → Show offline state in UI                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

4.2. Cache Names

const CACHE_NAME = 'daarion-v1';
const STATIC_CACHE = 'daarion-static-v1';
const PAGES_CACHE = 'daarion-pages-v1';

4.3. Precache List

const PRECACHE_URLS = [
  '/',
  '/city',
  '/offline',
  '/manifest.json',
  '/icons/icon-192x192.png',
  '/icons/icon-512x512.png'
];

5. OFFLINE PAGE

Файл: src/app/offline/page.tsx

Простий екран: - DAARION логотип - "Ви офлайн" - "Перевірте підключення до інтернету" - Кнопка "Спробувати знову"


6. HEAD METADATA

В layout.tsx:

<head>
  <link rel="manifest" href="/manifest.json" />
  <meta name="theme-color" content="#0c4a6e" />
  <link rel="apple-touch-icon" href="/icons/apple-touch-icon.png" />
  <meta name="apple-mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
  <meta name="apple-mobile-web-app-title" content="DAARION" />
</head>

7. SW REGISTRATION

В src/lib/pwa.ts:

export function registerServiceWorker() {
  if (typeof window === 'undefined') return;
  if (!('serviceWorker' in navigator)) return;

  // Only in production
  if (process.env.NODE_ENV !== 'production') {
    console.log('SW: Skipping registration in development');
    return;
  }

  window.addEventListener('load', async () => {
    try {
      const registration = await navigator.serviceWorker.register('/sw.js');
      console.log('SW: Registered', registration.scope);
    } catch (error) {
      console.error('SW: Registration failed', error);
    }
  });
}

8. TESTING CHECKLIST

8.1. DevTools → Application

  • [ ] Manifest loads correctly
  • [ ] Icons display properly
  • [ ] Service Worker is active
  • [ ] Cache Storage has expected caches

8.2. Install Prompt

  • [ ] Chrome shows "Install app" option
  • [ ] Safari iOS shows "Add to Home Screen"
  • [ ] App opens in standalone mode

8.3. Offline Mode

  • [ ] / loads from cache
  • [ ] /city loads from cache
  • [ ] /city/general shows chat offline state
  • [ ] API calls show appropriate error

8.4. Lighthouse

  • [ ] PWA score > 90
  • [ ] Performance > 80
  • [ ] Accessibility > 90

9. LIMITATIONS (MVP)

  • ❌ No push notifications (future phase)
  • ❌ No background sync
  • ❌ No offline message queue
  • ❌ No IndexedDB for offline data

10. FUTURE ENHANCEMENTS

  1. Push Notifications
  2. Web Push API
  3. VAPID keys
  4. Notification preferences

  5. Background Sync

  6. Queue messages when offline
  7. Sync when back online

  8. IndexedDB

  9. Cache chat history
  10. Offline-first architecture

  11. App Badges

  12. Unread message count on icon