This page was generated based on a 100% coding agent's review. No human change was involved.
Squillify C4 architecture
1. Scope
This page describes Squillify with the C4 model:
- System context: the people and outside services around Squillify.
- Containers: the applications and data services that run separately.
- Components: the main parts inside the web service and the projection worker.
- Code hotspots: the rules that protect security, billing, and availability.
| Label | Meaning |
|---|---|
| Included | Part of the running platform. |
| Separate switch | Built, and turned on only for that capability. |
| Optional | Used when that option is configured. |
| External | Operated outside the main Squillify service. |
The stores in the diagrams are separate jobs. They may sit with the same provider, but their access, retention, and integrity rules stay different.
2. Summary
Squillify is a multi-tenant platform. It offers deterministic, metered MicroSkills to AI agents over REST and the Model Context Protocol, and it gives people a tenant workspace and a separate operator workspace.
- Two web applications: one for the public site and tenants, one for operators.
- One Java service that runs as either the web runtime or a projection worker, never both in the same process.
- PostgreSQL keeps tenant records, access, entitlements, quotas, commercial records, invoices, billable usage, and the models used for reporting.
- A Redis-compatible store handles rate limits, concurrency, caches, and a fast quota path. PostgreSQL remains the record that can correct it.
- Kafka carries telemetry. It is not the billing record and it is not the invoice archive.
- Object storage has three jobs: temporary tenant files, telemetry archives, and signed invoice documents.
- Heavy document and media work runs in separate workers. Those calls are authenticated and have no silent local fallback.
- Clerk identifies people. Stripe handles payments. Operations metrics are collected separately from customer traffic.
- Support tickets, including image and PDF attachments and ticket email, are part of the platform. Public and automated ticket creation stay closed.
- Capability Sets add a bundle of skills on top of the skills granted directly to an API key.
- Formula and diagram rendering uses separate renderers. If a renderer is down, that render fails rather than guessing a result.
A successful billable response does not get ahead of the PostgreSQL billing record. Streams, caches, and archives can make the platform faster or more durable. They do not replace that record.
3. System context
| Who or what | Relationship |
|---|---|
| AI agents | Discover contracts and run MicroSkills with a Squillify API key. |
| Tenant users | Manage keys, capabilities, usage, files, and the subscription. |
| Platform operators | Run tenants, plans, trust, telemetry, commerce, and support. |
| Clerk | Identifies people. Tenant access and operator access stay separate. |
| Stripe | Takes payments and subscriptions. Incoming notices are signature-checked before they are stored and processed. |
| Hosting | Runs the web service, the projection worker, both websites, and optional workers. |
| PostgreSQL | Holds the authoritative records and durable work queues. |
| Redis-compatible store | Handles admission, caches, and the fast quota path. |
| Kafka | Moves telemetry and feeds an independent archive. |
| Object storage | Holds temporary files, telemetry archives, support attachments, and invoice documents as separate jobs. |
| Heavy workers | Run bounded document and media operations outside the web service. |
| Operations stack | Collects metrics, shows health, and alerts operators. |
| Email provider | Sends support mail and, when configured, product messages. It is never the record of payment, access, or tickets. |
| Formula and diagram renderers | Render those formats over HTTP. They are not a fallback for the heavy workers. |
Who talks to Squillify at 100 percent.
Loading diagram.
AI agents, tenant users, and platform operators use Squillify. Squillify uses identity, payments, heavy workers, managed data services, operations metrics, support email, and optional formula and diagram rendering.
4. Containers
| Part | Role |
|---|---|
| Public and tenant website | Catalog, pricing, and the tenant workspace. |
| Operator website | Separate site for internal operations. |
| Web runtime | APIs, skill execution, control planes, files, billing intake, and telemetry intake. |
| Projection worker | Turns stored usage deliveries into reporting models. It does not serve customer APIs. |
| Heavy workers | Document and media engines outside the web runtime. |
| Formula and diagram renderers | External renderers with no local substitute. |
| PostgreSQL | System of record for tenants, billing, files metadata, and reporting models. |
| Redis-compatible store | Limits, leases, caches, and the fast quota path. |
| Kafka | Telemetry transport and the source for the telemetry archive. |
| Temporary file store | Tenant file bytes. The database owns who the file belongs to. |
| Telemetry archive | Compressed telemetry objects, indexed in the database. |
| Financial document archive | Create-only invoice and credit-note files, switched on separately. |
| Operations stack | Health and metrics. Push-based export is optional and off unless configured. |
How the services are separated at 100 percent.
Loading diagram.
Agents and the two websites reach the web runtime. The web runtime uses identity, payments, Redis, PostgreSQL, Kafka, three object stores, and heavy workers. A separate projection worker reads durable deliveries from PostgreSQL and writes reporting models back. Operations metrics are collected from both runtimes.
The two process roles are separate deployments, even though they share one program:
- The web runtime serves APIs. The projection worker only updates reporting models.
- The projection worker does not accept Kafka traffic and does not serve customer routes.
- Telemetry is accepted by the web runtime, stored durably, and then projected.
- The telemetry archive is also in the web runtime, with its own consumer and object store.
- An invoice is saved in the database together with a task to archive it. The file is written afterward and can be retried without undoing the invoice.
5. Inside the web runtime
The web runtime is easier to read as several contracts than as one diagram.
Who is allowed in
Each kind of caller uses its own door. A person's login is not an API key. An API key is not an operator login. A payment notice is accepted without a login, and it is still signature-checked.
| Door | Who it admits |
|---|---|
| Support | Tenant and operator ticket routes. Public ticket creation stays closed. |
| Metrics | Operations collection, with its own token. |
| Webhooks | Identity, payment, and email notices. Each one is signature-checked. |
| Operators | Operator login, limited to the operator organization. |
| Public | Catalog, pricing, health, and public downloads that carry their own signed token. |
| Tenant workspace | Tenant login, resolved to that tenant. |
| Files | API key for file routes. A login token is refused there. |
| Skill runtime | API key for execution and the agent protocol. |
Separate doors for each kind of caller at 100 percent.
Loading diagram.
An incoming request is routed to the public site, a person login, a signed webhook, the file API, the skill runtime, or the closed public support door.
Running a skill
Agents get three stable operations: search, read a contract, and execute. The catalog can grow without turning every skill into a separate tool. Search, contract, and execution use the same access decision, including skills inherited from a Capability Set.
What happens when an agent runs a skill at 100 percent.
Loading diagram.
The agent is authenticated, admitted under rate and concurrency limits, then checked for access and quota. The skill runs locally or through a heavy worker. Usage is written to PostgreSQL before success is returned.
For a billable call the order is fixed: reserve quota, run the skill, save the usage record, settle the quota, then report success. If the usage record cannot be confirmed, the reservation is released and the caller is asked to retry.
Limits
Plan limits live in PostgreSQL. The fast path can answer from the Redis-compatible store when that path is healthy. If it is not, the database path remains. Pressure on the service can also shed load without treating that as a billing event.
Usage and reporting
Billing record and later reporting at 100 percent.
Loading diagram.
The invocation writes the billing record to PostgreSQL. A separate telemetry stream is accepted and queued, then a projection worker builds reporting models.
The usage ledger is the billing record. Reporting models are built afterward. They do not replace the ledger.
Telemetry archive
Telemetry archive at 100 percent.
Loading diagram.
Telemetry is batched, privacy-mapped, and stored as compressed objects. PostgreSQL keeps the index. Replay and erasure update that index rather than treating the object store as the only record.
A record that cannot be archived is kept as a failure and then acknowledged. If the object or its index cannot be saved, the batch is retried. The object store alone is not the index.
Invoices
Invoices and their files at 100 percent.
Loading diagram.
Commercial changes and signed payment notices update PostgreSQL. An invoice is issued there with an archive task. A later worker writes a create-only document file and stores a verified receipt. The file step does not undo the invoice.
Invoice files are not taken from the telemetry stream. They follow the invoice record. If the file store is unavailable, the invoice remains issued and the file is retried. A conflicting file is quarantined rather than overwritten. This archive is switched on only with its own document store.
Files
Temporary files at 100 percent.
Loading diagram.
An upload records ownership in PostgreSQL and bytes in object storage. Downloads use a signed token. Cleanup repairs records that no longer match stored bytes.
Temporary files, telemetry archives, and invoice documents do not share one retention rule. They stay separate jobs even when an environment places more than one of them with the same storage provider.
Heavy workers
Parsers, codecs, and office engines that need a lot of memory or native code do not run inside the web service. Each family is its own service, with its own workspace, and it is reached only through Squillify. The platform decides which published build is allowed to run. The worker does not share the API process disk, and it cannot see another tenant's files except the bytes Squillify sends for that one job.
The families, taken from the skills catalog, are:
| Worker | Engine | What it does |
|---|---|---|
| Document analysis | PDF and office parsers | Inspect a PDF, check its structure, extract layout, images, and form fields, fill a form, split or merge pages, render pages, and create a workbook. |
| PDF tables | A dedicated table engine | Extract ruled and borderless tables from a PDF. This stays separate from general PDF analysis. |
| HTML to PDF | A pinned headless browser | Turn HTML or Markdown into a PDF. Each call gets a fresh browser context. Remote pages, local file addresses, and unsandboxed browsing are refused. |
| Office rendering | A pinned office suite | Convert a DOCX document to PDF in a fresh process and user profile. |
| Office parsing | An isolated office parser | Inspect and extract content from office documents without rendering them. |
| Image rasters | A bounded image library | Inspect a raster image, preflight it, resize, crop, rotate, flip, convert format, strip metadata, and compare pixels. It does not decode PDF, SVG, raw camera files, or the other formats outside its allowlist. |
| OCR | A dedicated text-recognition engine | Read text from an image or scanned page. It does not share the image-raster worker, its credentials, or its capacity. |
Formula rendering and diagram rendering sit beside this list, not inside it. They are lighter HTTP renderers. If one of them is down, that render fails rather than being invented locally.
A heavy-worker call at 100 percent.
Loading diagram.
The web runtime checks the worker identity and approved build, sends a bound request, and receives the result only through Squillify file handling. There is no path that runs the same engine inside the web service.
Every worker of this kind follows the same shape:
- A dedicated service and a short-lived workspace that is cleaned up after each job.
- A pinned build and a signed identity. Rollout and rollback select those exact builds, not a floating name.
- Explicit limits for CPU, memory, concurrent jobs, queue size, deadline, and how many bytes the workspace may hold.
- It runs as an unprivileged user, with a read-only root disk, no extra operating-system privileges, and no access to the host disk.
- It has no outbound network by default. Any exception is a named destination list and a distinct caller identity.
- The temporary workspace is bounded, emptied at startup, emptied after each job, and swept if a job is abandoned.
- The connection is mutually authenticated. The worker's network name must match the expected identity exactly. Each request is also bound to its contents and protected against replay, even on a private network.
- A readiness check reports only whether the worker has capacity. An identity check returns the attested build. Neither check returns file contents, secrets, or tenant data.
The platform keeps a declaration for each worker. A call is refused unless every identity field matches:
| Declared fact | What it fixes |
|---|---|
| Worker identity | Which service this declaration belongs to. |
| Address | Where that service is reached. |
| Network identity | The exact authenticated name the connection must present. |
| Image and manifest | The approved build and the signed description of that build. |
| Allowed operations | Which jobs this worker may perform. |
| Engine inventory | Which engines and versions that build contains. |
| Time and size limits | How long a job may run and how large its input and output may be. |
| Capacity | How many jobs may run or wait at once. |
| Tenant activation | Which tenants are allowed to use this worker. |
If any of those fields do not match, the worker is unavailable. Squillify does not quietly run the same job inside the web service instead.
While a job runs, the platform records how many jobs are active, how deep the queue is, how often work is rejected or times out, how long it takes, whether the circuit is open, restarts, workspace size, output size, and failed identity checks. Alerts cover a worker that stays saturated, restarts in a loop, presents the wrong identity, times out too often, fails to clean up, or loses readiness.
Logs name the worker, the request, a tenant pseudonym, the operation, the status, the duration, and the byte counts. They do not include the file contents, file names, paths, credentials, the raw tenant identifier, or the worker's own error body.
A new build is activated only after its identity and readiness have been checked, and first for a limited set of tenants. Widening that set is a separate step. Rolling back restores the previous approved build and its signed description. The engine inventory is recorded for every build that is promoted.
Errors and operations
Every response can carry a request id. Public errors name the problem and whether a retry makes sense. They do not include stack traces, queries, file paths, secrets, or another tenant's data. Health information is public. Detailed metrics require the operations token.
6. Projection worker
Projection worker at 100 percent.
Loading diagram.
A scheduler reads durable deliveries from PostgreSQL, projects them into reporting models, and exposes only health and protected metrics.
This process does not include the web runtime's APIs, login, skill execution, or telemetry intake. That keeps reporting work from opening those doors.
7. Rules that must hold
| Area | Rule |
|---|---|
| Billing | No billed success before the usage record is durable. A reservation is settled or released once. |
| Quota | The database and the fast path agree, and the database can correct the fast path. |
| API keys | Secrets stay hashed. Revocation is honored. One tenant cannot use another's key. |
| Skill access | Search, the contract, and execution show the same permissions. |
| Runaway use | Abuse locks are enforced from the database. A blocked call is not billed. |
| Telemetry intake | Duplicates are safe. Poison records are recorded. The projection worker owns its backlog. |
| Telemetry archive | A batch is finished only when the object and its index are saved. |
| Invoices | The invoice and its archive task commit together. Files are create-only and verified. |
| Heavy workers | No call without attested identity. No local fallback. |
| Files | Ownership, token scope, retention, and size limits are enforced. |
| Doors | Login, API keys, webhooks, files, metrics, and support do not share one authorization rule. |
8. Decisions
| Decision | What it means |
|---|---|
| One policy for REST and the agent protocol | Both paths share access, limits, execution, metering, and errors. |
| PostgreSQL is the commercial record | Plans, entitlements, invoices, and billable usage live there. Streams and reports are copies. |
| Uncertain billing fails closed | The caller does not get a billed success when the ledger write is uncertain. |
| Two process roles | The web runtime and the projection worker share a build, not a running application. |
| Three object-storage jobs | Temporary files, telemetry, and invoices keep different access and retention rules. |
| Two archive paths | Telemetry is archived from the stream. Invoices are archived from the database task. |
| Invoice files are written after the record | A file-store problem does not undo the invoice. Conflicts are quarantined. |
| Heavy engines stay outside | Large or native work runs in isolated services. |
| The fast path is explicit | The Redis-compatible store is used for speed only with a fallback and a way to reconcile. |
| Present is not the same as switched on | Code can exist while a surface stays off until it is deliberately enabled. |
9. Where each kind of data lives
| Data | Record of truth | Copies |
|---|---|---|
| People and organizations | Identity provider, with a link stored by Squillify | The signed-in session |
| API keys | PostgreSQL | Short-lived caches that can be invalidated |
| Skill descriptions | The published skill catalog | Public pages and search indexes |
| Which skills a key may run | PostgreSQL | The access decision used at runtime |
| Plans, subscriptions, and adjustments | PostgreSQL, with the payments provider for provider-managed objects | Workspace views |
| Quota | PostgreSQL | Fast-path counters and reconciliation evidence |
| Billable usage | PostgreSQL usage ledger | Telemetry and reporting models |
| Telemetry stream | Kafka, for its retention window | Acceptance state and archive objects |
| Telemetry archive index | PostgreSQL | Compressed archive objects |
| Temporary files | Object storage for bytes, PostgreSQL for ownership | Signed download tokens |
| Invoices and credit notes | PostgreSQL | A signed document plus a verified receipt |
| Provider payments | Payments provider | Stored references and applied local effects |
| Support tickets | PostgreSQL | Search projections and email delivery |
| Operations metrics | Runtime meters | The operations stack and operator views |