Concepts, value, and typical clone scenarios — less code.
Concepts, value, and typical clone scenarios — less code.
Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Profiling and optimization strategies for Ring Platform integrators. For operator-facing overview, see Performance patterns. For production infrastructure, see Deployment performance.
Use Founder / Developer tabs in the docs sidebar to filter this page.
Ring Platform does not use client-side Firestore. Firebase is Admin SDK only via lib/firebase-admin.server.ts. Client Firebase code is limited to public/firebase-messaging-sw.js for FCM.
| Factor | Effect |
|---|---|
| Server Components default | Most routes ship zero client JS for pure rendering |
Request dedup (cache()) | One Firestore read per document per server render |
| Cached store catalog | Product list shared across API route and server action |
| Batched Web Vitals | One analytics POST per page load instead of five |
| Provider SSOT | Single credit-balance stream, single tunnel connection |
| Build-time Firebase mock | Static pages build without live credentials |
Profiling and optimization strategies for Ring Platform integrators. For operator-facing overview, see Performance patterns. For production infrastructure, see Deployment performance.
Use Founder / Developer tabs in the docs sidebar to filter this page.
Ring Platform does not use client-side Firestore. Firebase is Admin SDK only via lib/firebase-admin.server.ts. Client Firebase code is limited to public/firebase-messaging-sw.js for FCM.
| Factor | Effect |
|---|---|
| Server Components default | Most routes ship zero client JS for pure rendering |
Request dedup (cache()) | One Firestore read per document per server render |
| Cached store catalog | Product list shared across API route and server action |
| Batched Web Vitals | One analytics POST per page load instead of five |
| Provider SSOT | Single credit-balance stream, single tunnel connection |
| Build-time Firebase mock | Static pages build without live credentials |
Profiling and optimization strategies for Ring Platform integrators. For operator-facing overview, see Performance patterns. For production infrastructure, see Deployment performance.
Use Founder / Developer tabs in the docs sidebar to filter this page.
Ring Platform does not use client-side Firestore. Firebase is Admin SDK only via lib/firebase-admin.server.ts. Client Firebase code is limited to public/firebase-messaging-sw.js for FCM.
| Factor | Effect |
|---|---|
| Server Components default | Most routes ship zero client JS for pure rendering |
Request dedup (cache()) | One Firestore read per document per server render |
| Cached store catalog | Product list shared across API route and server action |
| Batched Web Vitals | One analytics POST per page load instead of five |
| Provider SSOT | Single credit-balance stream, single tunnel connection |
| Build-time Firebase mock | Static pages build without live credentials |
| Web Vitals batch |
| Client tab |
components/providers/web-vitals-provider.tsx (1.5s debounce) |
| Session refetch | Client tab | features/auth/components/session-provider.tsx (15 * 60, no focus/offline) |
Full operator narrative: Performance patterns.
cache() in Server ComponentsCache scope is the current Server Component render pass only. For cross-request caching, use Next 16 Cache Components ('use cache') or revalidate exports.
During next build, lib/firebase/build-mock.server.ts detects NEXT_PHASE=phase-production-build and returns mock Firestore/Auth instances. Chainable where() / orderBy() / limit() return empty result sets — no credentials required for SSG.
findDocById over filtering by id in queryDocs.filters + pagination at the database layer — do not fetch-all-then-filter in application code.entities — no manual cache for basic cases.Do not call db.users.findById() or similar. The API is db().findDocById('users', id) or db().queryDocs({ collection, filters, … }).
getSharedPgPool() in lib/database/shared-pg-pool.ts returns the connected adapter pool after initializeDatabase(). new Pool( must appear only under lib/database/ — enforced by gate 7 of scripts/validate-provider-ssot.sh.
Routine persistence: db().createDoc / findDocById / queryDocs / transaction.
Before merging hook or provider changes:
Seven gates — full table in Best practices. Key paths:
SessionProvider → features/auth/components/session-provider.tsx (duplicates under components/providers/ deleted)useVendorStatus → sole owner of fetch('/api/vendor/status')useCreditBalance → sole owner of '/api/wallet/credit/balance' string in TS/TSXPages in app/ are Server Components unless marked 'use client'. Client boundaries belong on interactive leaves: checkout forms, maps, wallet UIs, admin dashboards.
WebVitalsProvider batches Core Web Vitals into one debounced POST /api/analytics/web-vitals. There is no per-metric POST from useReportWebVitals directly — do not document or implement five separate analytics calls per page load.
For build analysis:
Firebase cache metrics (getCacheMetrics()) are dev-only when FIREBASE_DEBUG_LOGS=true.
| Web Vitals batch |
| Client tab |
components/providers/web-vitals-provider.tsx (1.5s debounce) |
| Session refetch | Client tab | features/auth/components/session-provider.tsx (15 * 60, no focus/offline) |
Full operator narrative: Performance patterns.
cache() in Server ComponentsCache scope is the current Server Component render pass only. For cross-request caching, use Next 16 Cache Components ('use cache') or revalidate exports.
During next build, lib/firebase/build-mock.server.ts detects NEXT_PHASE=phase-production-build and returns mock Firestore/Auth instances. Chainable where() / orderBy() / limit() return empty result sets — no credentials required for SSG.
findDocById over filtering by id in queryDocs.filters + pagination at the database layer — do not fetch-all-then-filter in application code.entities — no manual cache for basic cases.Do not call db.users.findById() or similar. The API is db().findDocById('users', id) or db().queryDocs({ collection, filters, … }).
getSharedPgPool() in lib/database/shared-pg-pool.ts returns the connected adapter pool after initializeDatabase(). new Pool( must appear only under lib/database/ — enforced by gate 7 of scripts/validate-provider-ssot.sh.
Routine persistence: db().createDoc / findDocById / queryDocs / transaction.
Before merging hook or provider changes:
Seven gates — full table in Best practices. Key paths:
SessionProvider → features/auth/components/session-provider.tsx (duplicates under components/providers/ deleted)useVendorStatus → sole owner of fetch('/api/vendor/status')useCreditBalance → sole owner of '/api/wallet/credit/balance' string in TS/TSXPages in app/ are Server Components unless marked 'use client'. Client boundaries belong on interactive leaves: checkout forms, maps, wallet UIs, admin dashboards.
WebVitalsProvider batches Core Web Vitals into one debounced POST /api/analytics/web-vitals. There is no per-metric POST from useReportWebVitals directly — do not document or implement five separate analytics calls per page load.
For build analysis:
Firebase cache metrics (getCacheMetrics()) are dev-only when FIREBASE_DEBUG_LOGS=true.
| Web Vitals batch |
| Client tab |
components/providers/web-vitals-provider.tsx (1.5s debounce) |
| Session refetch | Client tab | features/auth/components/session-provider.tsx (15 * 60, no focus/offline) |
Full operator narrative: Performance patterns.
cache() in Server ComponentsCache scope is the current Server Component render pass only. For cross-request caching, use Next 16 Cache Components ('use cache') or revalidate exports.
During next build, lib/firebase/build-mock.server.ts detects NEXT_PHASE=phase-production-build and returns mock Firestore/Auth instances. Chainable where() / orderBy() / limit() return empty result sets — no credentials required for SSG.
findDocById over filtering by id in queryDocs.filters + pagination at the database layer — do not fetch-all-then-filter in application code.entities — no manual cache for basic cases.Do not call db.users.findById() or similar. The API is db().findDocById('users', id) or db().queryDocs({ collection, filters, … }).
getSharedPgPool() in lib/database/shared-pg-pool.ts returns the connected adapter pool after initializeDatabase(). new Pool( must appear only under lib/database/ — enforced by gate 7 of scripts/validate-provider-ssot.sh.
Routine persistence: db().createDoc / findDocById / queryDocs / transaction.
Before merging hook or provider changes:
Seven gates — full table in Best practices. Key paths:
SessionProvider → features/auth/components/session-provider.tsx (duplicates under components/providers/ deleted)useVendorStatus → sole owner of fetch('/api/vendor/status')useCreditBalance → sole owner of '/api/wallet/credit/balance' string in TS/TSXPages in app/ are Server Components unless marked 'use client'. Client boundaries belong on interactive leaves: checkout forms, maps, wallet UIs, admin dashboards.
WebVitalsProvider batches Core Web Vitals into one debounced POST /api/analytics/web-vitals. There is no per-metric POST from useReportWebVitals directly — do not document or implement five separate analytics calls per page load.
For build analysis:
Firebase cache metrics (getCacheMetrics()) are dev-only when FIREBASE_DEBUG_LOGS=true.
import { getCachedDocument, getCachedCollection } from '@/lib/services/firebase-service-manager'
// Multiple calls during one render → one Firestore read
const entity = await getCachedDocument('entities', 'abc123')
const same = await getCachedDocument('entities', 'abc123') // cache hit
import { db } from '@/lib/database'
const result = await db().queryDocs({
collection: 'entities',
filters: [{ field: 'status', operator: '==', value: 'active' }],
orderBy: [{ field: 'createdAt', direction: 'desc' }],
pagination: { limit: 20, offset: 0 },
})
if (!result.success) throw result.error ?? new Error('Query failed')
import { getSharedPgPool } from '@/lib/database'
// PostGIS / raw SQL only — not for routine CRUD
const pool = await getSharedPgPool()
./scripts/validate-provider-ssot.sh
export const revalidate = 60 // ISR — revalidate every 60s
export const dynamic = 'force-dynamic' // user-specific, no cache
npm run build
npm run analyze
import { getCachedDocument, getCachedCollection } from '@/lib/services/firebase-service-manager'
// Multiple calls during one render → one Firestore read
const entity = await getCachedDocument('entities', 'abc123')
const same = await getCachedDocument('entities', 'abc123') // cache hit
import { db } from '@/lib/database'
const result = await db().queryDocs({
collection: 'entities',
filters: [{ field: 'status', operator: '==', value: 'active' }],
orderBy: [{ field: 'createdAt', direction: 'desc' }],
pagination: { limit: 20, offset: 0 },
})
if (!result.success) throw result.error ?? new Error('Query failed')
import { getSharedPgPool } from '@/lib/database'
// PostGIS / raw SQL only — not for routine CRUD
const pool = await getSharedPgPool()
./scripts/validate-provider-ssot.sh
export const revalidate = 60 // ISR — revalidate every 60s
export const dynamic = 'force-dynamic' // user-specific, no cache
npm run build
npm run analyze
import { getCachedDocument, getCachedCollection } from '@/lib/services/firebase-service-manager'
// Multiple calls during one render → one Firestore read
const entity = await getCachedDocument('entities', 'abc123')
const same = await getCachedDocument('entities', 'abc123') // cache hit
import { db } from '@/lib/database'
const result = await db().queryDocs({
collection: 'entities',
filters: [{ field: 'status', operator: '==', value: 'active' }],
orderBy: [{ field: 'createdAt', direction: 'desc' }],
pagination: { limit: 20, offset: 0 },
})
if (!result.success) throw result.error ?? new Error('Query failed')
import { getSharedPgPool } from '@/lib/database'
// PostGIS / raw SQL only — not for routine CRUD
const pool = await getSharedPgPool()
./scripts/validate-provider-ssot.sh
export const revalidate = 60 // ISR — revalidate every 60s
export const dynamic = 'force-dynamic' // user-specific, no cache
npm run build
npm run analyze