Core systems (frontend & backend)

PURPOSE

This documents the implemented scaffolding aligned with Practical-core-systems.md: centralized logging, config feature flags, a standard API error shape, and frontend data/prefetch helpers. It maps to observability (§1), feature flags (§8), error system (§15), and preparation for data sync / prefetch (§17, §19).


Frontend (frontend/lib/)

Logging — lib/logger.ts

  • API: logger.debug, logger.info, logger.warn, logger.error(message, context?)
  • Behavior: debug / info are no-ops in production; warn / error always run. Optional context is JSON-serialized.
  • Intent: Replace ad-hoc console.* so Sentry or another sink can be wired in one place later.

Feature flags — lib/flags.ts

  • API: getFlag(name), getFlags()
  • Flags: newUI, aiStreaming, debugMode (typed as FeatureFlagName).
  • Env (build-time):
FlagEnvironment variableDefault
newUINEXT_PUBLIC_FF_NEW_UIfalse
aiStreamingNEXT_PUBLIC_FF_AI_STREAMINGfalse
debugModeNEXT_PUBLIC_FF_DEBUG_MODEfalse
  • Truthy values: 1, true, yes, on (case-insensitive). Falsy: 0, false, no, off, empty/unset.
  • Note: Dev-only toggles in the dev overlay are separate from these product flags.

Error system — lib/errors/

  • AppErrorBody: { code: string; message: string; status: number; details?: unknown } — matches Nest error responses after the global filter.
  • AppError: throwable client error with the same fields.
  • isAppErrorBody(value): type guard for JSON.
  • parseApiError(res) / parseApiErrorBody(res): parse a failed fetch Response.
  • throwIfNotOk(res): throws AppError when !res.ok.

Example:

import { throwIfNotOk } from "@/lib/errors"

const res = await fetch(url, options)
await throwIfNotOk(res)

Data layer prep — lib/data/

  • query-keys.ts stable queryKeys tree (auth, users, courses, institutions, documents) for future TanStack Query / SWR.
  • routes.ts appRoutes canonical paths (home, login, onboarding, dashboard, test).
  • use-app-prefetch.ts client hook useAppPrefetch()prefetchHref(href) using Next.js router.prefetch.

Example:

import { appRoutes, useAppPrefetch } from "@/lib/data"

const { prefetchHref } = useAppPrefetch()
// e.g. onMouseEnter={() => prefetchHref(appRoutes.dashboard)}

Backend (backend/src/common/)

Logging — common/logger/app-logger.ts

  • API: appLogger.debug, appLogger.log, appLogger.warn, appLogger.error(message, trace?, context?)
  • Wraps Nest Logger with optional JSON context on messages.

Error envelope — common/filters/app-exception.filter.ts

  • Registered globally in app.module.ts via APP_FILTER provider.
  • All thrown errors are normalized to JSON:
{
  "code": "UNAUTHORIZED",
  "message": "Human-readable message",
  "status": 401,
  "requestId": "uuid-v4-trace-id",
  "details": {}
}
  • requestId: A unique correlation ID attached to every request, used for cross-log tracing.
  • details is omitted when undefined.

Request Tracing & Logging — common/interceptors/logging.interceptor.ts

  • Global Interceptor: Captures every request/response cycle.
  • X-Request-ID: Generates or propagates a correlation ID for tracing.
  • Latency Tracking: Logs execution time for every endpoint.
  • Sanitization: Automatically masks sensitive fields (password, token, secret, key) in logs.

Security & Protection (backend/src/common/)

Tiered Rate Limiting

Configured via ThrottlerModule with three distinct tiers:

  • auth: 5 requests / 5 minutes (Strict protection for login/signup).
  • ai: 20 requests / 1 hour (Cost control for LLM usage).
  • default: 100 requests / 1 minute (General API protection).

Guards:

  • AuthThrottlerGuard: Tracks by IP or User ID for authentication routes.
  • AiThrottlerGuard: Specific limits for AI inference to manage provider costs.

Abuse Prevention — common/services/abuse-prevention.service.ts

  • Identity Blocking: Persistence-based blocking using the blocked_identities table.
  • Automated "Smart Ban": Automatically blocks IPs/Users for 24 hours if they trigger 5+ suspicious events (e.g., rate limit hits, failed logins) within 10 minutes.
  • Security Audit Log: Every suspicious event is logged to security_events for manual review.
  • Global Shield: GlobalAbuseGuard enforces blocks across all routes before any logic executes.

AI Cost Controls — backend/src/ai/ai.service.ts

  • Real-time Credit Guarding: Every AI request checks the user's subscription_usages.
  • Atomic Enforcement: Prevents credit overruns via atomic database increments.
  • Usage Cycles: Automatically tracks usage within monthly windows aligned with subscriptions.

Authentication (backend/src/auth/)

Secure cookie session flow

  • Login/signup issue two HTTP-only cookies:
    • access_token (short-lived, default 15 minutes)
    • refresh_token (long-lived, default 30 days)
  • Refresh tokens are stored only as hashes in auth_sessions.
  • Every refresh rotates the refresh token hash (replay-resistant rotation).
  • Logout clears cookies and removes active session rows.
  • Frontend auth UX is page-based (/login, /signup) with redirect continuation via next.
  • Unauthenticated protected access redirects to login; there is no in-page auth modal fallback.

Guard behavior

  • CookieAuthGuard validates access token + session row (auth_sessions) for protected routes.
  • If access token is expired and refresh token is valid, the guard auto-refreshes and reissues cookies.
  • If session is missing/expired/revoked, request is rejected as unauthorized.

Structured Notes (backend/src/notes/)

FEAT-59 module behavior

  • Module: NotesModule registered in AppModule.
  • Guarding: all endpoints use CookieAuthGuard; ownership derives from request.user.user_id.
  • Endpoints:
    • GET /notes, POST /notes
    • GET /notes/:id, PATCH /notes/:id, DELETE /notes/:id
    • POST /notes/:id/references
    • PATCH /notes/:id/references/:referenceId
    • DELETE /notes/:id/references/:referenceId
    • PATCH /notes/:id/canvas

Related repo doc

  • Practical-core-systems.md (repo root) — full checklist; this page only describes what is implemented today.

Not implemented here (see Practical-core-systems.md)

  • Sentry & Metrics (OpenTelemetry/Prometheus)
  • Job Queues idempotency (Queues are implemented but idempotency logic is pending)
  • Per-user / remote feature flags
  • Zod (or similar) on every route
  • TanStack Query / SWR (queryKeys and prefetch hook are ready for when you add them)

QA Coverage Expectations

Test IDScenarioExpected Result
SEC-01Correlation ID InjectionAll response headers contain X-Request-ID and logs show the same UUID.
SEC-02Tiered Rate LimitingAuth routes block after 5 attempts; AI routes block after 20.
SEC-03Automated Smart Ban5 rate-limit hits in 10m results in a 24h entry in blocked_identities.
SEC-04Global Abuse ShieldBlocked IP/User receives 403 Forbidden on any endpoint.
SEC-05AI Cost EnforcementUser with 0 credits receives 402 Payment Required on AI endpoints.
SEC-06Data SanitizationLogs for /auth/login do not contain plaintext passwords.