Skip to content
bitzorcas
中EN

Concept

Website public site and growth engine

Source-verified guide to public content, contact leads, anonymous analytics, experiments, funnels, short links, privacy endpoints, jobs, and GA boundaries.

Last updated

Website is genuinely composed by both API Host and JobHost. It delivers content management/public reads, contact submission, anonymous telemetry, Web Vitals, experiments, funnels, short links, analytics marts, sitemap generation, and selected privacy endpoints. It does not include a website frontend, and consent, lead management, and scheduled publishing are not complete.

1. Architecture

Browser / administrator

API Host endpoints

Website Application

Website aggregates

Website ports

Infrastructure adapters

Dual ORM / Redis / Data Protection

JobHost

Handwritten endpoints handle public workflows that need HTTP context; seven growth-management requests use [GenerateEndpoint]. API Host registers analytics, GeoIP, short links, cache invalidation, and persistence. JobHost runs mart and sitemap work.

2. Code map

Project/locationCurrent responsibility
ContractsDTOs, public ports, permissions, features, integration events
DomainContent, Lead, AnalyticsEvent, Experiment, Funnel, ShortLink, mart rows
ApplicationContent/contact/growth handlers and job executors
InfrastructureStores, sanitizer, queue/DLQ, journey, GeoIP, protection, sitemap
API HostPublic/admin endpoints, visitor middleware, output cache, composition
JobHostQuartz adapters, mart rebuild, sitemap submission consumers

3. Capability matrix

AreaEvidence in sourceNot currently guaranteed
ContentDraft/update/schedule/publish/unpublish/archive, public query/feed/sitemapAutomatic due publishing, versions, approval, preview token
ContactCAPTCHA, field protection, save, notificationIdempotency, notification reconciliation, lead-management API
AnalyticsBounded in-memory queue, batch store, mart, RUM, funnel, experimentConsent, crash-safe intake, durable DLQ, exactly once
PrivacySubject/visitor reads and soft deletionAnonymous ownership proof, consent record, statutory workflow evidence
Short linksHTTP(S), random/custom code, expiry, cache, QRDestination policy, revoke/update, tenant ownership, click availability
GovernanceSix permissions, five default-off featuresRuntime feature enforcement

4. HTTP surface

Handwritten routes include /api/public/content*, /api/public/contact*, sitemap, /api/telemetry/*, public assignment, /r/{code}, and self-service privacy. Content management explicitly requires website.content.read/manage.

Generated growth routes derive website.growth.manage or website.analytics.read through IAuthorizedRequest; those match the catalog. Features have no equivalent execution evidence.

5. Public and tenant model

Content, Lead, and ShortLink have no TenantId and are platform-global. Analytics, Experiment, Funnel, and mart rows carry TenantId. Public analytics gets Website:PublicTenantId, defaulting to literal public.

Authenticated analytics uses ICurrentTenant. Internal assignment/privacy messages still carry tenant IDs, but host endpoints construct them from server configuration or trusted identity; do not expose those messages directly.

6. Actual telemetry example

The current path does not query consent. It builds context from middleware-owned visitor/session and coarse device/region fields.

Submit anonymous telemetry
// ① Visitor, session, and public tenant are server-derived.
AnalyticsCaptureContext context = WithPublicTenant(
AnonymousVisitorContextMiddleware.BuildCaptureContext(httpContext, visitor),
configuration);
// ② The handler limits 1..50 and rejects forged experiment-assigned events.
Result result = await mediator.Send(
new CaptureTelemetryBatchCommand(context, body.Events),
httpContext.RequestAborted);
// ③ Success means accepted by this process, not persisted.
return result.ToHttp(httpContext);

7. Protection is not a privacy system

Lead name/contact/inquiry use ASP.NET Core Data Protection. Analytics omits full IP/user-agent, strips URL query/fragment, and validates custom dimensions against a low-cardinality schema and heuristic PII checks.

These are minimization measures, not lawful basis, consent, withdrawal, retention, or subject verification. Visitor Journey remains in Redis for 400 days. There is no consent aggregate or retention job.

8. Reliability semantics

Analytics intake uses an in-process Channel. Full queue returns AnalyticsQueueFull; graceful stop drains; process crash loses queued data. Exhausted writes enter a per-instance ConcurrentDictionary DLQ that also disappears on restart.

If click telemetry is full, short-link redirect fails. If contact notification throws after saving, the request can fail after a lead already exists. These are current product semantics.

9. Governance gaps

Five default-off features—public content, contact, analytics, experiments, and short links—are declared but not consumed in runtime paths. Deployment cannot use them to close routes.

LeadRead/LeadManage and domain transitions exist, but no lead list/detail/decrypt/assignment/follow-up handler or endpoint exists. The catalog is not a delivered CRM.

10. Deep dives

11. Source checks

Terminal window
# ① Inspect handwritten and generated routes.
rg -n "Map(Get|Post|Put|Delete)|GenerateEndpoint" \
src/Hosts/BitzOrcas.Api/Endpoints/Website* src/Platform/Website -g '*.cs'
# ② Feature usage should currently remain catalog-only.
rg -n "WebsiteFeatures\." src tests -g '*.cs' --glob '!**/bin/**' --glob '!**/obj/**'
# ③ Scheduled has no due-content publisher.
rg -n "PublishStatus\.Scheduled|ScheduleContent|Scheduled" src/Platform/Website src/Hosts -g '*.cs'

12. Reading method

Start at endpoint authentication, authorization, rate limiting, and body limits; follow trusted-context construction into handlers and aggregate invariants; then inspect store transaction/tenant predicates, cache/events/jobs/failure recovery, and tests. A DTO or XML comment alone is not delivery evidence.

13. Change-review questions

  • Does a new public route pass through visitor middleware and auto-pageview?
  • Is the resource platform-global or tenant-owned?
  • Does its feature actually execute in the request path?
  • Is an anonymous identifier being mistaken for authorization?
  • Does success mean accepted, committed, or external effect complete?
  • Is state/event atomicity proven with an outbox?
  • What happens to Redis, Channel, and DLQ state after restart?
  • Can the Data Protection key ring be restored?
  • Are HTML, URL, XML, and SVG outputs context-safe?
  • Does erase cover queues, DLQ, marts, caches, and backup expiry?
  • Do jobs define lease, duplication, and partial success?
  • Do tests cover both ORMs, multiple instances, and real Host routes?

Back to platform modules

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%