schema/deployment.rs
1//! The assembled deployment configuration — a **composition** concern.
2//!
3//! [`Config`] names a source, the sinks, and the indexes to build. It sits
4//! *above* the backend crates: sources and sinks depend only on the
5//! `schema-core` vocabulary (`IndexSchema`, `IndexMapping`, the newtypes), never
6//! on this crate, so a backend can't reach the top-level config. The composition
7//! root (CLI/daemon) translates `Config` into the backend-facing subsets each
8//! side needs (a source spec, the per-sink configs).
9//!
10//! These types were lifted out of `schema-core` for exactly that reason —
11//! keeping the cross-cutting vocabulary at the bottom layer while the
12//! composition lives next to the daemon.
13
14mod conversion;
15mod projection;
16mod sink;
17mod source;
18
19pub use sink::Sink;
20pub use source::Source;
21
22use std::collections::BTreeMap;
23use std::net::SocketAddr;
24
25use schema_core::{FailurePolicy, IndexSchema, common};
26use serde::{Deserialize, Serialize};
27
28/// A whole deployment: where data comes from, where it goes, and what to build.
29///
30/// Secrets are deferred (a literal or an environment reference, see
31/// [`Secret`](schema_core::Secret)), so a serialized `Config` carries only the
32/// literals it was given and resolves the rest at runtime. Debug output redacts
33/// literal secrets either way.
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct Config {
36 pub source: Source,
37 pub sinks: BTreeMap<common::SinkName, Sink>,
38 pub indexes: BTreeMap<common::IndexName, Index>,
39 /// What to do when a sink rejects a document at the item level. The default
40 /// for every index; override per index with [`Index::on_error`].
41 #[serde(default)]
42 pub on_error: FailurePolicy,
43 /// Bind addresses for the operational HTTP surfaces. Read by the binary, not
44 /// the daemon — transport is the binary's concern. Env/flag overrides win;
45 /// see [`ServerConfig`].
46 #[serde(default)]
47 pub server: ServerConfig,
48}
49
50/// Bind addresses for the two operational HTTP surfaces, as configured in
51/// `flusso.toml`'s `[server]` table. Parsed and validated at config-read time
52/// (see `schema_config_toml`'s `BindAddress`), so these are real socket
53/// addresses by the time they reach the binary, which layers `FLUSSO_*` env vars
54/// and CLI flags on top (which win).
55#[derive(Debug, Clone, Default, Serialize, Deserialize)]
56pub struct ServerConfig {
57 /// Public, read-only surface (`/healthz`, `/readyz`, `/status`, `/metrics`).
58 #[serde(default, skip_serializing_if = "Option::is_none")]
59 pub public_address: Option<SocketAddr>,
60 /// Private, Basic-auth control surface (`/indexes`, `/reindex`).
61 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub private_address: Option<SocketAddr>,
63}
64
65/// One index in a [`Config`], paired with whether it is built on this run.
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct Index {
68 pub enabled: bool,
69 pub schema: IndexSchema,
70 /// Per-index override of [`Config::on_error`]. `None` inherits the global
71 /// policy. Lives here (not in [`IndexSchema`]) on purpose: it's operational,
72 /// not part of the document shape, so changing it does not alter the index
73 /// mapping hash or trigger a reindex.
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub on_error: Option<FailurePolicy>,
76}