Skyeline
A platform for versioning prompts, routing LLM requests across providers, and observing the latency and token usage of agent and RAG applications.
- Intended user
- Engineering teams that need a controlled way to develop prompts and operate LLM-backed applications across environments.
- Current status
- Deployed prototype
- Deployed on Google Cloud Run, although the service may currently be disabled. It has no users or sales.
Ownership
I originated and built this project from scratch, from the product idea and architecture through implementation. I use Claude Code and Codex as implementation tools; no human collaborator directed the work.
Architecture
A public-safe view of the system boundaries and the paths between them.
- Component 01Interface
Next.js dashboard
Human interface for prompt lifecycle, approvals, playground runs, and trace inspection.
- Component 02Interface
SDK consumer
An application-scoped TypeScript client using bearer authentication.
- Component 03Control
NestJS API boundary
Fastify HTTP layer with validation, authentication, workspace context, and authorization guards.
- Component 04Service
Prompt control plane
Versioning, lifecycle transitions, diffs, rollbacks, and approval workflows.
- Component 05Service
LLM gateway
Provider registry, request normalization, streaming, and trace capture.
- Component 06Service
Provider adapters
A common boundary for supported model providers and provider-specific translation.
- Component 07Data
PostgreSQL
Workspace-scoped prompts, credentials, approvals, and observability records behind repositories.
- Component 08Output
External model providers
Third-party inference endpoints reached only through the gateway adapters.
Data and control paths
- Next.js dashboardNestJS API boundary
- SDK consumerNestJS API boundary
- NestJS API boundaryPrompt control plane
- NestJS API boundaryLLM gateway
- Prompt control planePostgreSQL
- LLM gatewayPostgreSQL
- LLM gatewayProvider adapters
- Provider adaptersExternal model providers
Evidence boundary
What this case study establishes, and what it deliberately does not claim.
Verified evidence
Claims supported by inspected artifacts, repeatable checks, or the project's current state.
Prompt lifecycle
The repository implements versioned prompts, diffs, rollbacks, tags, template variables, lifecycle states, and approval workflows.
Basis: Private repository structure, service modules, and tests reviewed for this case study.
Multi-provider runtime
A provider registry and adapters normalize requests, support streaming, and persist latency and token metadata for inspection.
Basis: Gateway architecture, adapter modules, and observability test inventory.
Tenant and credential controls
Workspaces and applications form the tenancy boundary, with role checks and per-workspace encryption for provider credentials.
Basis: Authentication, authorization, workspace, application, and crypto modules.
Contract-driven SDK
The public TypeScript SDK is generated from an explicit OpenAPI operation allowlist, then wrapped with application scoping, typed errors, retry behavior, templates, streaming, and webhook verification utilities.
Basis: OpenAPI generation pipeline, SDK package, and SDK test suites.
Cloud deployment design
The deployment workflow builds a container, runs database migrations as a separate Cloud Run job, and deploys the API service with managed secrets.
Basis: Repository deployment workflow and architecture documentation.
Known limitations
What has not been established, validated with users, or measured in production.
Current service state
The prototype was deployed to Google Cloud Run, but its current availability and full hosted flow have not been re-verified.
Outcome boundary
This case study reports implemented engineering surfaces only. It makes no claims about adoption, traffic, commercial outcomes, or current uptime.
Private implementation
The source repository and service configuration remain private. This module contains no copied source, private endpoints, identifiers, credentials, or operational data.
Verification boundary
The repository contains broad automated test coverage, but this portfolio content does not claim that every suite or hosted workflow is currently passing.
Engineering decisions
The design choices, reasoning, and tradeoffs that shaped the system.
- 01
Make the public API opt-in
Generate the SDK from an allowlist of public OpenAPI operation identifiers.
Why: Internal endpoints stay private unless they are deliberately reviewed and added to the contract.
Tradeoff: Every intended public operation requires an explicit contract update and regeneration step.
- 02
Keep provider logic behind adapters
Route model requests through a registry of provider adapters and expose a normalized gateway surface.
Why: Application code can use one execution path while provider-specific translation remains isolated.
Tradeoff: A normalized interface cannot erase every provider difference, so unsupported capabilities still need clear runtime errors.
- 03
Treat prompts as governed artifacts
Model prompt changes as immutable versions with draft, active, and archived states plus approval workflows.
Why: A prompt change becomes reviewable and reversible instead of silently replacing the current behavior.
Tradeoff: The lifecycle adds workflow overhead for simple experiments, which the playground must keep lightweight.
- 04
Separate schema changes from startup
Run database migrations as a dedicated deployment job before updating the application service.
Why: Startup remains deterministic and failed migrations stop deployment before new application code receives traffic.
Tradeoff: The deployment pipeline must coordinate two artifacts and surface migration failures clearly.
- 05
Scope credentials to the tenant boundary
Encrypt provider credentials with AES-256-GCM using keys derived per workspace through HKDF, and decrypt them only for execution.
Why: A stored credential is not plaintext, and derived keys reduce cross-workspace blast radius.
Tradeoff: Master-key protection and rotation remain operational responsibilities beyond application-layer encryption.
Reliability & safety
Controls that make failures visible, bounded, and recoverable.
- Testing
Unit boundaries
Focused suites cover authorization guards, crypto helpers, provider adapters, prompt behavior, gateway orchestration, error mapping, and SDK utilities.
- Testing
Database-backed integration
Integration and end-to-end suites exercise service boundaries with isolated PostgreSQL infrastructure through Testcontainers.
- Safety boundary
Public-surface contract checks
Contract tests compare the generated SDK surface with the allowlisted public OpenAPI document to catch accidental exposure or drift.
- Failure handling
Transport failure handling
The SDK has dedicated resilience tests for retry classification, backoff, retry guidance, streaming, and typed error behavior.
- Observability
Structured diagnostics
Backend flows use structured logging with stable context, duration fields, sensitive-header redaction, and explicit outcome logging.
- Testing
Deployment gates
Repository workflows define lint, type-check, unit, integration, end-to-end, build, contract, and packaging checks before deployment or release steps.
Synthetic evaluation
A reproducible, non-production signal with its methodology and limits attached.
Synthetic observability fixture
A six-row, public-safe fixture demonstrates how the case study can explain trace aggregation without presenting synthetic values as product performance.
Evaluation set: 6 synthetic traces
- Synthetic traces
- 6
- Synthetic success rate
- 83.3%
- Synthetic median latency
- 895 ms
- Synthetic token volume
- 2,640
Fixture row count, not traffic.
5 success rows and 1 error row in the fixture.
Median of the six invented latency values.
Sum of invented input and output token values.
Methodology
- 01Define six fictional traces across three supported provider adapters with explicit latency, token, and outcome fields.
- 02Compute counts, success rate, median latency, and total tokens in this module from those exported fixture rows.
- 03Use the output only to demonstrate the observability model and the UI's aggregation concepts.
Interpretation limits
- The fixture is not a benchmark, load test, production sample, or customer dataset.
- Provider, network, model, prompt, and cache behavior are intentionally uncontrolled, so the values cannot support performance comparisons.
- A credible future evaluation would define a repeatable workload, pin models and regions, record warm and cold runs separately, and report distributions rather than a single aggregate.
Current state
- State 01The system was deployed to Google Cloud Run, but the deployment may need to be re-enabled before a live walkthrough.
- State 02There are currently no users, sales, or adoption metrics, so this is presented as a deployed independent prototype.
- State 03The repository remains private while architecture and public-safe product material can be shared.
Demo & public material
Only reviewed, public-safe material is linked from this page.
- Public materialPublic
Architecture and case study
Public-safe system flow, engineering decisions, security boundaries, and limitations.
- Public materialPublic
Synthetic trace fixture
Six fictional rows plus exported aggregation logic for reproducible display metrics.
- Public materialPlanned
Recorded walkthrough
Publish only after the hosted flow is re-verified and demo data is reviewed for disclosure safety.
- Public materialNot public
Source repository
Implementation remains private. No repository link or copied source is included.
Next steps
- Next 01Re-enable and verify the full hosted flow before publishing any live link.
- Next 02Run design-partner sessions to validate the prompt approval and observability workflows.
- Next 03Add usage-based feedback loops before treating the current feature set as a stable product surface.