From b0117b7c848a3b53958a640df388038a13127766 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 28 May 2026 23:00:48 +0800 Subject: [PATCH] =?UTF-8?q?[=E6=96=B0=E5=A2=9E]=20=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=8B=B1=E6=96=87=E7=89=88=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/design/development.md | 300 ++++++++++++++++-- docs/en/design/index.md | 155 ++++++++- docs/en/design/release-model.md | 70 +++- docs/en/guide/first-site.md | 94 +++++- docs/en/guide/server.md | 88 ++++- docs/en/guide/upgrade.md | 58 +++- ...Unified OpenResty Binary Control Scheme.md | 84 +++++ docs/en/reference/api.md | 26 +- docs/en/reference/cli.md | 53 ++++ docs/en/reference/index.md | 10 +- docs/en/reference/repository.md | 53 ++-- 11 files changed, 870 insertions(+), 121 deletions(-) create mode 100644 docs/en/plan/Agent Unified OpenResty Binary Control Scheme.md diff --git a/docs/en/design/development.md b/docs/en/design/development.md index d0a6dfec..a8957322 100644 --- a/docs/en/design/development.md +++ b/docs/en/design/development.md @@ -1,31 +1,295 @@ # Development Constraints -After `1.0.0`, OpenFlare development prioritizes stability, upgrade and rollback reliability, documentation accuracy, test coverage, and small iterations inside the existing boundary. +You will learn: The admission criteria for OpenFlare code modifications, backend/Agent/frontend tiered constraints, data model boundaries, API conventions, database migration requirements, and test delivery baselines. + +This document integrates the original development specifications, frontend specifications, and development plans, and serves as the engineering constraints entry point for OpenFlare after `1.0.0`. + +## Current Conclusions + +* The mainline capabilities of the first to sixth versions have all been completed. +* `1.0.0` is the current official baseline. +* Procedural tasks of completed stages are subject to code, tests, and Git history. +* Priority for new work is given to bug fixes, maintainability improvements, and documentation and test reinforcement. + +Current Development Priorities: + +1. Stability. +2. Upgrade and rollback link reliability. +3. Document accuracy. +4. Test coverage reinforcement. +5. Small iterations within existing boundaries. ## Change Admission -Before implementing a requirement, check: +Before new requirements enter implementation, judge them in the following order: -1. Whether it fits the product boundary. -2. Whether it follows Server, Agent, and frontend development rules. -3. Whether it risks the publish, sync, rollback, or upgrade flow. -4. Whether deployment, configuration, or README docs need updates. +1. Whether it fits the [Product Boundary](./index.md). +2. Whether it follows the backend, Agent, and frontend constraints in this document. +3. Whether it risks breaking the existing publish, sync, rollback, or upgrade main links. +4. Whether it requires synchronized updates to deployment, configuration, README, or documentation site pages. -If a requirement expands the boundary or introduces new infrastructure, update design documentation first. +If a requirement expands the boundary or introduces new infrastructure, the design documentation must be updated first before starting implementation. -## Database Migrations +Any changes merged into the official baseline must at least meet: -Any table, index, column type, sharding, or internal persistence metadata change must bump the database version and include an explicit migration from the previous version. +* Does not break the Agent heartbeat, synchronization, publishing, and rollback main links. +* Does not break the existing OpenResty main configuration hosting model. +* Does not degrade the existing availability of the overview, node details, and access analysis. +* Has tests or joint debugging verification commensurate with the risks. +* Documentation remains consistent with the code. -Migrations must validate the upgraded schema. Startup must stop if migration or validation fails. +## Technical Baseline -## Frontend Rules +Server: -`openflare_server/web` is the frontend baseline: +* Go 1.25+ +* Gin +* GORM +* SQLite / PostgreSQL +* Existing login system -* Routes and layouts live in `app/`. -* API calls are centralized under `lib/api/`. -* Business logic belongs in `features/`. -* Server state uses TanStack Query. -* Forms use React Hook Form and Zod. -* Theme supports `light`, `dark`, and `system`. +Agent: + +* Single binary +* Node-local execution +* Control OpenResty binary via `openresty_path` or default `openresty` +* Docker deployment uses the Agent image with built-in OpenResty, and does not have the Agent control a separate OpenResty container + +Frontend: + +* Next.js 15 App Router +* React 19 +* TypeScript 5 +* Tailwind CSS 4 +* TanStack Query +* React Hook Form + Zod +* Zustand only used for lightweight client status +* ESLint + Prettier +* Vitest + Testing Library + Playwright +* pnpm + +## Server Layering + +| Directory | Responsibility | +| --- | --- | +| `controller/` | Parameter parsing, calling services, returning responses | +| `service/` | Business logic, verification, transaction orchestration, rendering | +| `model/` | Model definition and persistence | +| `router/` | Route registration | +| `middleware/` | Auth, authorization, rate limiting, and other cross-cutting logic | +| `common/` | Configuration, global state, and initialization entry points | +| `utils/` | Pure utility functions and general helpers | + +It is forbidden to accumulate business logic in `controller/`, forbidden to implement business flows in `middleware/`, and forbidden to add platform-level abstractions for simple requirements. + +## Agent Layering + +The Agent maintains its existing module boundaries: + +* `config` +* `heartbeat` +* `sync` +* `openresty` / `nginx` +* `state` +* `httpclient` +* `protocol` +* `internal/updater` + +Requirements: + +* Each module has a single responsibility. +* External command calls are centrally encapsulated. +* State persistence and configuration persistence are separated. + +## Frontend Layering + +Recommended directories: + +```text +app/ +components/ +features/ +lib/ +hooks/ +store/ +types/ +styles/ +tests/ +``` + +Responsibility constraints: + +* `app/`: Routes, layouts, page assembly. +* `features/`: Organize modules by business domains. +* `components/`: Reuse components across features. +* `lib/`: Request client, environment variables, utility functions, constants. +* `store/`: A small amount of cross-page UI state. +* `types/`: Shared type definitions. + +Page files are only responsible for obtaining routing parameters, organizing page structures, and calling feature components; they should not handwrite complex API details, complex form verification logic, or maintain a large amount of mutually coupled local states. + +## Data Model Specifications + +Currently active entities: + +* `proxy_routes` +* `origins` +* `config_versions` +* `nodes` +* `auth_sources` +* `external_accounts` +* `node_system_profiles` +* `apply_logs` +* `tls_certificates` +* `managed_domains` +* `node_request_reports` +* `node_access_logs` +* `node_metric_snapshots` +* `traffic_analytics_rollups` +* `node_health_events` +* `options` + +General constraints: + +* No new platform-oriented objects are added unless explicitly required by the design document. +* `origins` only serves as a reusable origin address directory, and the fields are kept lightweight. +* `proxy_routes` uses "site configuration" as the aggregation boundary and must contain a unique `site_name` and a non-empty `domains` list. +* Each domain in `proxy_routes.domains` must be globally unique, and the first item in the list is treated as the primary domain. +* `proxy_routes` continues to allow saving one or more upstream addresses for load balancing, but does not introduce an independent `origin_pool`. +* The legacy `domain` field can only be used as a compatible mirror of `domains[0]`; new code must not continue to use this field as the unique business input. +* If `proxy_routes` is associated with `origins`, it must also save the `origin_url` that can be directly rendered. +* Upstreams uniformly use named `upstream` + keepalive; for a single upstream carrying a base path or query, the original URI should be added back to `proxy_pass`. For multiple upstreams, only pure `scheme://host[:port]` is allowed. +* Rate limits, reverse proxy, and cache configurations currently belong to the site-level `proxy_routes`. +* HTTPS certificate binding must be saved on a per-domain basis through `domain_cert_ids` parallel to `domains`; domains not bound to a certificate must not participate in HTTPS rendering. +* `config_versions` must save complete snapshots and rendering results. +* There can only be one activated version globally at a time. +* Rollback is achieved by reactivating older versions. +* `nodes` only retains control plane status and low-frequency summaries. +* Observability data must be associated with nodes and time windows, and snapshots and aggregation results use an append-only model. +* Original access details must have a controlled retention policy. +* `auth_sources` only saves management console third-party login source configurations, currently supporting `github` and `oidc`. +* `external_accounts` is the unique source of binding between third-party accounts and local users; the old `users.github_id` is only used for compatible migration and must not be used as the business input for the new login flow. + +## Database Migration + +Any modification involving table structures, indexes, column types, sharding rules, or internal persistence metadata must upgrade the database version number in sync. + +The database version number is defined in `openflare_server/model`, and it must not rely solely on `AutoMigrate` for implicit upgrades of existing databases. + +Every time the database version number is upgraded, an explicit migration method from the previous version to the new version must be added. The migration method must contain validation logic after the upgrade; only when the validation passes can the new database version record be written. + +After starting the new package, the database's current version must be checked first, and then upgraded step by step in order to the target version; skipping intermediate upgrade steps to directly write the target version is prohibited. + +An empty database initialization can directly establish the current version structure, but the same-version validation must still be executed after the initialization is completed, and the current database version must be persisted. + +If the migration or validation fails, the startup process must abort, and the database version record must not be upgraded. Submissions involving database version changes must add corresponding migration tests or equivalent regression tests. + +## API and Authentication + +The management console and Agent APIs uniformly use JSON. Both success and failure must return a clear `message`: + +```json +{ + "success": true, + "message": "", + "data": {} +} +``` + +Conventions: + +* Agent APIs are uniformly placed under `/api/agent/*`. +* The overview and node details prioritize using dedicated aggregation interfaces. +* Management console mutation APIs uniformly use `POST`; read-only APIs use `GET`. +* The management console continues to reuse existing logins, roles, and Sessions. +* Third-party login uniformly enters through authentication source APIs; authentication source management interfaces must require Root Session. +* `/api/status` can only return the public fields of enabled authentication sources, and must not return the Client Secret. +* When a third-party account is not bound and registration is closed, a process to bind to an existing account should be provided, and users must not be automatically created. +* Official Agent requests uniformly use the node-exclusive `agent_token`. +* The first access can use the global `discovery_token`. +* Agent request headers uniformly use `X-Agent-Token`. + +It is forbidden to expose remote shell or arbitrary command execution entries, forbidden to print full Tokens in logs, and forbidden to save main configuration templates that bypass placeholder constraints. + +## Publishing and Runtime + +The publishing logic must maintain: + +* Read all enabled `proxy_routes` during publishing. +* Read OpenResty main configuration parameters, reverse proxy performance parameters, and cache parameters at the same time. +* Generate complete OpenResty configuration. +* Calculate `checksum`. +* Write to `config_versions`. +* Activate the version by switching `is_active`. + +Version constraints: + +* The version number format is fixed as `YYYYMMDD-NNN`. +* Do not modify historical versions online. +* Do not make differentiated versions grouped by nodes. +* Preview and diff are read-only capabilities and do not generate release records. + +The Agent must satisfy: + +* Read or generate local `node_id` after startup. +* Periodic heartbeat and synchronization. +* Conventional synchronization prioritizes judging based on the version summary returned by the heartbeat. +* Back up old files first when discovering a new version. +* Write main configurations, route configurations, and necessary certificate files. +* Execute `openresty -t -c ` after writing the new configuration, and then reload; direct startup of OpenResty is allowed when reload finds that it is not running. +* If the activation of the new configuration fails, the Agent must first try to restore execution with the target configuration, then roll back to the old configuration and pull up OpenResty again. +* Report warning when OpenResty recovers normally after rollback; report failure when it still cannot recover after rollback. +* Once a target `version + checksum` fails to apply and rolls back, the Agent must block repeated applications of this target in its local state. + +## Frontend Requests, State, and Types + +All API requests must be uniformly routed through `lib/api/`: + +* Uniformly handle the `success/message/data` response structure. +* Uniformly handle authentication failure, network exceptions, and general error messages. +* Centralize maintenance of resource interfaces and request paths. + +State Layering: + +* Server state: TanStack Query. +* Page temporary state: Component-internal `useState`. +* Cross-page UI state: Zustand. + +Strict TypeScript mode is required; abuse of `any` is prohibited. API responses, form inputs, and business entities must have explicit types. + +## Forms, Interaction, Style, and Themes + +Forms uniformly use React Hook Form and Zod. + +High-risk operations must have double confirmation, show the name of the operation object, and clearly provide success and failure feedback. + +Style principles: + +* Uniformly use Tailwind CSS and the existing token system. +* Prioritize reusing existing basic components and layout components. +* Maintain consistent visual hierarchy, padding, and semantic colors. + +Theme requirements: + +* Support `light`, `dark`, and `system` simultaneously. +* User choices must be persisted. +* Try to avoid theme flickering on the first screen. + +## Test and Delivery + +* Key business logic must have unit tests or equivalent regression tests. +* Agent main link modifications must verify synchronization, application, and rollback. +* Frontend pages must cover at least loading states, empty states, error states, and success feedback. +* When the Go version is adjusted, check `go.mod`, Dockerfile, and CI workflows in sync. + +## Subsequent Maintenance + +Subsequent planning is no longer maintained in the form of "major version phase documents", but adopts the following methods: + +* Product boundary changes: Update [Product Boundary](./index.md). +* Engineering constraint changes: Update this document. +* Deployment and configuration changes: Update [Deployment Guide](../guide/deployment.md), [Configuration Items](../reference/configuration.md), and README. + +If explicit new stage goals appear in the future, add dedicated planning documents separately; do not pile completed historical plans back into this document. + +The model boundary of the current special topic "Site-level Rules and Configuration Interface Reconstruction" has been integrated into the [Product Boundary](./index.md). When executing, still advance in the order of data models, interfaces, frontend pages, migration tests, and document linkage. diff --git a/docs/en/design/index.md b/docs/en/design/index.md index a86ef39d..f8e6c02d 100644 --- a/docs/en/design/index.md +++ b/docs/en/design/index.md @@ -1,21 +1,150 @@ # Product Boundary -OpenFlare is a self-hosted OpenResty control plane for single-team or single-organization operations. It unifies reverse proxy configuration, node synchronization, certificate management, and basic observability. +You will learn: What OpenFlare is, what problems it solves, who the target users are, what the current stable capabilities are, and which design boundaries cannot be bypassed during implementation. -Stable capabilities: +OpenFlare is a self-hosted OpenResty control plane oriented toward single-team or single-organization internal operation and maintenance (O&M) scenarios. It resolves the issues of scattered management in reverse proxy configuration, node synchronization, certificate hosting, configuration release/rollback, and basic observability. + +## Project Positioning + +OpenFlare is suitable for teams that need to centrally manage multiple OpenResty proxy nodes: + +* Want to maintain reverse proxy site configurations using a management console. +* Want every configuration change to have a complete version, preview, activation, and rollback. +* Want nodes to actively sync configuration, rather than having the control plane SSH into nodes to execute commands. +* Want to manage TLS certificates, domain assets, node statuses, and basic access analytics within the same system. + +OpenFlare is currently not positioned as a general-purpose log platform, service mesh, Kubernetes Ingress Controller, or multi-tenant cloud platform. + +## Target Users + +| User | Needs | +| --- | --- | +| Self-hosted users | Quickly deploy a visual OpenResty control plane | +| Internal O&M teams | Manage multiple reverse proxy nodes, certificates, and configuration versions | +| Development teams | Provide a unified entry point and basic access analytics for internal services | +| Contributors | Fix defects, strengthen tests, and improve documentation within clear boundaries | + +## Current Stable Capabilities | Capability | Description | | --- | --- | -| Reverse proxy management | Site-level configuration with multiple domains and origins | -| Configuration versions | Preview, publish, activate, and rollback | -| Agent sync | Registration, heartbeat, sync, and apply result reporting | -| OpenResty management | Main template, performance options, cache options, and Lua assets | -| HTTPS/TLS | Certificate storage and per-domain binding | -| Basic observability | Request rollups, resource snapshots, health events, and access analytics | -| Node management | Node state, tokens, deployment, and update flow | +| Reverse Proxy Rule Management | Uses site configuration as the aggregation boundary, supporting multi-domain and origin configuration | +| Site-level Configuration | One rule corresponds to one site, which can bind one or more domains and share site-level configuration | +| Origin Management | Maintains a lightweight origin directory and allows sites to save renderable origin snapshots | +| Configuration Versioning | Supports preview, publishing, activation, immutable history, and rollback | +| Agent Synchronization | Supports registration, heartbeat, synchronization, application result reporting, and self-updating | +| OpenResty Hosting | Manages main configuration templates, performance parameters, cache parameters, and Lua resources | +| HTTPS/TLS | Hosts certificates and domain assets, and binds certificates on a per-domain basis | +| Basic Observability | Aggregates node requests, resource snapshots, health events, and access analytics | +| Node Management | Node status, token systems, deployment, and update links | +| Console Frontend | Next.js-based official management console | +| Auth Source Login | Supports configuring GitHub and standard OIDC login entries as authentication sources, allowing third-party accounts to bind to existing local users | -Default operating model: +Default working method: -* All nodes consume the same globally active version. -* Server stores configuration and state, but does not SSH into nodes. -* Agent is the only controlled entry point on each node. +* All nodes consume the same globally activated version. +* The Server saves configuration and status, and does not directly manage nodes via SSH. +* The Agent is the only controlled landing entry point on the node side. + +## Typical Use Cases + +| Scenario | Description | +| --- | --- | +| Unified Entry for Internal Services | Expose multiple internal HTTP services through a unified domain and certificate | +| Config Sync for Multi-node Reverse Proxy | Multiple OpenResty nodes consume the same activated configuration | +| Config Change Review | View preview or diff before publishing, and retain immutable history after publishing | +| Quick Rollback | Reactivate an older version, letting the Agent pull and apply it | +| Certificate Hosting | Bind TLS certificates for different domains | +| Basic Observability | View node status, request aggregation, access analytics, and health events | + +## Core Objects + +Currently active entities: + +* `proxy_routes` +* `origins` +* `config_versions` +* `nodes` +* `auth_sources` +* `external_accounts` +* `node_system_profiles` +* `apply_logs` +* `tls_certificates` +* `managed_domains` +* `node_request_reports` +* `node_access_logs` +* `node_metric_snapshots` +* `traffic_analytics_rollups` +* `node_health_events` + +## Site Configuration Constraints + +`proxy_routes` is upgraded from a "single-domain rule" to a "site configuration" aggregate object. One record corresponds to one website, which can bind one or more domains and share a set of site-level configurations. + +Constraints: + +* `proxy_routes.site_name` is the unique business identifier of the website. +* `proxy_routes.domains` contains at least one domain, and `domains[0]` is used as the primary domain. +* Any domain can globally belong to only one `proxy_routes`. +* During the migration period, `proxy_routes.domain` can be kept as a mirror field of `domains[0]`, but business read/write and subsequent extensions must be based on `site_name` + `domains`. +* Site-level rate limits, reverse proxies, and cache configurations are currently shared by site and are not configured differently on a per-domain basis within the same website. +* HTTPS allows binding certificates per domain within the same site. + +## Origin Constraints + +`origins` only saves the origin address, display name, and remarks, and does not carry protocols, ports, paths, weights, or health check policies. + +`proxy_routes` can optionally associate an `origins` record to reuse the origin address; the rule still saves a complete `origin_url` snapshot to participate in rendering and version snapshots. + +Upstream constraints: + +* `proxy_routes` must contain at least one upstream address. +* To maintain compatibility with historical data, the `origin_url` main upstream field is retained, and multiple upstreams are allowed to be added within the same rule for load balancing. +* Upstreams are rendered uniformly as a named `upstream` with keepalive. +* A single upstream can carry a base path or query and append it in `proxy_pass`. +* Multiple upstreams are restricted to pure `scheme://host[:port]`. +* `proxy_routes.origin_host` is an optional field, used to override the `Host` request header when back-origin. +* All upstream addresses must be legal `http://` or `https://`. + +## HTTPS Constraints + +`proxy_routes.domain_cert_ids` is used to record domain-certificate bindings parallel to `domains`; a value of `0` indicates that HTTPS is not enabled for the domain, retaining only HTTP. + +During publishing rendering: + +* Domains with certificates are output as separate `443 ssl` `server` blocks grouped by certificate. +* Domains not bound to a certificate must not be automatically brought into HTTPS. +* All domains in `proxy_routes.domains` must be included in the same site configuration to avoid the same site being split in version snapshots. + +## Authentication Source Constraints + +`auth_sources` is the configuration object for third-party login entries on the management console, currently supporting only two types: `github` and `oidc`. Enabled authentication sources will be displayed on the login page. + +`external_accounts` saves the binding relationship between external accounts of authentication sources and local users. When a third-party account logs in for the first time: + +* If it is bound to a local user, it logs in directly. +* If there is an existing local login session, it binds to the current user. +* If it is not bound and registration is allowed, a normal user is automatically created and bound. +* If it is not bound and registration is closed, the user is only allowed to enter an existing local account and password to complete the binding. + +The old `users.github_id` only serves as a source for upgrade migration; new third-party account login and binding relationships must be based on `external_accounts`. + +## Version and Observability Constraints + +* `config_versions` must save complete snapshots, rendering results, and `checksum`. +* There can only be one activated version globally at a time. +* Rollback is achieved by reactivating older versions. +* `nodes` only carries control plane status and low-frequency summaries, not high-frequency observability facts. +* Metrics, trends, and access analytics prioritize server-side aggregation results, rather than temporary frontend statistics. +* Access details are only retained for controlled time windows, not evolving into a general-purpose log platform. + +## Documentation Maintenance Principles + +* Update this document when the product scope or system boundary changes. +* Update [System Architecture](./architecture.md) when the system structure or module responsibilities change. +* Update [Release Model](./release-model.md) when the release, synchronization, or rollback model changes. +* Update [Development Constraints](./development.md) when development constraints, code specifications, or interface conventions change. +* Update [Deployment Guide](../guide/deployment.md) and README when deployment methods change. +* Update [Configuration Reference](../reference/configuration.md) when configuration items change. +* Completed phases will no longer be backfilled in the form of "version plans". +* Before starting a new phase, complete the design first, then enter implementation. diff --git a/docs/en/design/release-model.md b/docs/en/design/release-model.md index c4be2922..1c0e603a 100644 --- a/docs/en/design/release-model.md +++ b/docs/en/design/release-model.md @@ -1,33 +1,71 @@ # Release Model -OpenFlare publishes complete configuration versions instead of modifying node configuration online. +You will learn: Why OpenFlare uses a complete configuration version as the release unit, and how publishing, activation, Agent application, and rollback work. + +OpenFlare's release model is centered on complete configuration versions rather than modifying node configurations online. + +Standard link: ```text -Edit rules -> Preview / diff -> Publish -> Create full version -> Activate -> Agent pulls -> Agent applies -> Agent reports +Modify rules -> Preview / View diff -> Publish -> Generate complete configuration version -> Activate version -> Agent pulls -> Local application -> Report result ``` -## Publish Rules +## Publishing Rules -Server must: +When publishing, the Server must: 1. Read all enabled `proxy_routes`. -2. Read the OpenResty main template and structured options. -3. Render the full OpenResty configuration. -4. Compute `checksum`. -5. Write `config_versions`. -6. Switch the active version. -7. Let Agents discover and apply it in later heartbeats. +2. Read the OpenResty main configuration template, performance parameters, cache parameters, and necessary Lua resources on the Server side. +3. Read domain and certificate binding relationships. +4. Render the complete OpenResty configuration. +5. Calculate the `checksum`. +6. Write to `config_versions`. +7. Switch the activated version. +8. Let the Agent discover and apply it in subsequent heartbeats. -Version numbers use `YYYYMMDD-NNN`. +The version number format is fixed as `YYYYMMDD-NNN`. + +## Preview and Publishing + +Preview and diff are read-only capabilities and do not generate release records. + +Publishing generates a new complete configuration version. The version must contain sufficient information so that future rollbacks can be re-applied based on historical snapshots, without relying on current mutable configurations. + +## Activating Version + +There can only be one activated version globally at a time.Differentiated versions grouped by nodes are currently not supported. + +The Agent obtains the activated version summary through the heartbeat; only when the remote version or checksum is inconsistent with the local state does the Agent enter the synchronization flow. ## Immutable History -Historical versions are immutable. Rollback reactivates an old version. +Historical versions are immutable. Rollback is not achieved by modifying older versions, but by reactivating older versions. -Only one global active version exists at a time. Node-specific version groups are not part of the current model. +The result of doing this is: -## Agent Apply Strategy +* Every version can be traced back. +* The rollback link is consistent with the ordinary release application link. +* The Agent does not need to understand "reverse patch", but only needs to apply a target version. -Agent backs up old files, writes the new main config, route config, certificates, and Lua assets, then validates and reloads. +## Agent Application Policy -If activation fails, Agent attempts to recover. A failed `version + checksum` is blocked locally until the remote active version or checksum changes. +When discovering a new version, the Agent will: + +1. Pull the details of the target version. +2. Back up old files. +3. Write the main configuration, route configurations, certificates, and necessary Lua resources. +4. Execute OpenResty configuration verification. +5. reload; if it is not started during runtime, try to start OpenResty with the current configuration. +6. Report success, warning, or failure. + +If the activation of the new configuration fails, the Agent must try to restore execution; report a warning when the rollback succeeds, and report a failure when it still cannot recover after rollback. + +Once a target `version + checksum` application fails and rolls back, the Agent will block repeated applications of this target in its local state. Only when the remote activated version or checksum changes is it allowed to try again. + +## Design Constraints + +* Publishing must read all enabled site configurations, rather than only rendering the modified object this time. +* Rollback is achieved by reactivating older versions, without modifying historical versions. +* The Agent API is fixed to use the node-exclusive `agent_token`; the first access can use the `discovery_token`. +* The Server does not provide remote shell or arbitrary command execution entries. +* The configuration version must save complete snapshots, rendering results, and `checksum`. diff --git a/docs/en/guide/first-site.md b/docs/en/guide/first-site.md index 38e92531..ea908cfb 100644 --- a/docs/en/guide/first-site.md +++ b/docs/en/guide/first-site.md @@ -1,32 +1,100 @@ -# Publish First Site +# Publishing Your First Configuration -OpenFlare publishes complete configuration versions. After editing a site, publish and activate a new version before Agents apply it. +You will learn: How to create your first site configuration, bind origins and certificates, publish a configuration version, and confirm that the Agent has applied it. + +OpenFlare's release link is centered on complete configuration versions. After modifying site configurations on the management console, you need to publish and activate the new version before the Agent pulls and applies it in subsequent heartbeats. + +## Pre-release Check + +Confirm that the following conditions are met: + +| Project | Expectation | +| --- | --- | +| Server | Can log into the management console | +| Agent | At least one node is online | +| Origin | The Agent node can access the origin address | +| Domain | The domain has been resolved to the OpenResty node, or you are ready to verify via local hosts / curl Host header | +| HTTPS | If HTTPS is required, the certificate has been uploaded or hosted | ## Create Site Configuration -Required fields: +When adding a site configuration on the management console, you need at least: | Field | Description | | --- | --- | -| Site name | Business-unique identifier; defaults to the primary domain when omitted | -| Domains | At least one domain; the first one is the primary domain | -| Origin URL | Valid `http://` or `https://` upstream URL | -| Enabled | Only enabled sites are rendered into releases | +| Site Name | Unique business identifier; defaults to the primary domain when omitted | +| Domains | At least one domain; the first item is treated as the primary domain | +| Origin URL | Valid `http://` or `https://` upstream address | +| Enabled | Only enabled site configurations participate in release rendering | -A domain can belong to only one site. +Example: + +| Field | Example | +| --- | --- | +| Site Name | `app` | +| Domains | `app.example.com` | +| Origin URL | `http://10.0.0.20:8080` | + +A domain can belong to only one site configuration. Site-level rate limits, reverse proxies, and cache configurations are shared by site. ## Bind Certificates -HTTPS certificates are bound per domain. Domains without certificates are not automatically rendered into `443 ssl` server blocks. +HTTPS certificates are bound per domain. Domains not bound to certificates will not be automatically placed in `443 ssl` server blocks. + +If a site contains multiple domains, the publishing rendering will generate HTTPS configurations grouped by certificate and ensure all domains still belong to the same site snapshot. ## Publish and Activate +Standard link: + ```text -Edit rules -> Preview / diff -> Publish -> Create full version -> Activate -> Agent pulls -> Agent applies -> Agent reports +Modify rules -> Preview / View diff -> Publish -> Generate complete configuration version -> Activate version -> Agent pulls -> Local application -> Report result ``` -Server reads enabled sites, OpenResty template, performance options, and cache options, renders a full configuration, computes `checksum`, writes `config_versions`, then switches the active version. +When publishing, the Server reads all enabled site configurations, OpenResty main configuration templates, performance parameters, and cache parameters, renders the complete OpenResty configuration, calculates the `checksum`, writes to `config_versions`, and then switches the activated version. -## Verify +## Verify Results -Check that the node is online, the node version matches the active version, the latest apply log succeeded, and the version page marks the new version as active. +After publishing, confirm on the management console: + +| Location | Expected Result | +| --- | --- | +| Node List | Node is online | +| Node Details | The current version is consistent with the activated version | +| Apply Logs | The most recent application succeeded | +| Version Page | The new version is in the activated state | + +Confirm the Agent logs on the node: + +```bash +journalctl -u openflare-agent -n 100 --no-pager +``` + +Access using the domain: + +```bash +curl -I http://app.example.com +``` + +If the domain has not been officially resolved yet, you can temporarily specify the Host header to access the node IP: + +```bash +curl -I -H 'Host: app.example.com' http://NODE_IP +``` + +HTTPS verification: + +```bash +curl -I https://app.example.com +``` + +## Rollback + +If the target version application fails and rolls back, the Agent will block repeated applications of the same `version + checksum` locally until the activated version or checksum on the control plane changes. + +To roll back to an older version: + +1. Open the configuration version page. +2. Find the previous confirmed working historical version. +3. Reactivate that version. +4. View the node application records to confirm that the Agent applied it successfully. diff --git a/docs/en/guide/server.md b/docs/en/guide/server.md index 79feeb61..5df200a6 100644 --- a/docs/en/guide/server.md +++ b/docs/en/guide/server.md @@ -1,18 +1,23 @@ -# Run Server +# Starting the Server -OpenFlare Server is the Gin + GORM control plane. It owns the web console, management API, Agent API, configuration rendering, release publishing, and state storage. +You will learn: How to build the management console frontend from source, start OpenFlare Server, select SQLite or PostgreSQL, and access Swagger. -## Requirements +OpenFlare Server is a Gin + GORM monolithic control plane, responsible for the management console UI, management APIs, Agent APIs, configuration rendering, version releases, data storage, and aggregated queries. -| Item | Requirement | -| --- |-------------------------------------------------------| -| Go | `1.25+` | -| Node.js | `18+` | -| Database | Writable SQLite path or reachable PostgreSQL instance | +## Prerequisites -Set `SESSION_SECRET` explicitly in production and prefer PostgreSQL. +| Project | Requirement | +| --- | --- | +| Go | `1.25+` | +| Node.js | `18+` | +| pnpm | Recommended to use the pnpm declared by the project via `corepack enable` | +| Database | SQLite file directory is writable, or an accessible PostgreSQL instance | -## Build Frontend +In production environments, it is recommended to explicitly configure `SESSION_SECRET` and prioritize PostgreSQL. + +## Build the Management Console Frontend + +The Go Server hosts the static artifacts in `openflare_server/web/build`. Before starting from source, build the frontend first: ```bash cd openflare_server/web @@ -21,32 +26,81 @@ pnpm install pnpm build ``` -## Run from Source +Common frontend checks: + +```bash +pnpm lint +pnpm typecheck +pnpm test +``` + +## Start with SQLite ```bash cd openflare_server -export SESSION_SECRET='replace-with-random-string' +export SESSION_SECRET='replace-with-a-long-random-string' export SQLITE_PATH='./openflare.db' export LOG_LEVEL='info' -# Optional PostgreSQL: -# export DSN='postgres://openflare:secret@127.0.0.1:5432/openflare?sslmode=disable' go run . ``` -The default port is `3000`. +Listens on port `3000` by default. Access: + +```text +http://localhost:3000 +``` + +## Start with PostgreSQL + +```bash +cd openflare_server +export SESSION_SECRET='replace-with-a-long-random-string' +export DSN='postgres://openflare:secret@127.0.0.1:5432/openflare?sslmode=disable' +export LOG_LEVEL='info' +go run . +``` + +`DSN` takes precedence over SQLite once set. When `DSN` and the legacy-named `SQL_DSN` both exist, `DSN` takes precedence. + +If the target PostgreSQL database is empty and the local `SQLITE_PATH` file exists, the Server will attempt to migrate SQLite data to PostgreSQL during the startup phase and output the migration progress in the logs. + +## Command Line Parameters + +```bash +go run . --port 3000 --log-dir ./logs +``` + +| Parameter | Action | Default Value | +| --- | --- | --- | +| `--port` | Specify the Server listening port | `3000` | +| `--log-dir` | Specify the log directory | Empty (outputs to standard output) | +| `--version` | Output the version and exit | `false` | +| `--help` | Output the help information and exit | `false` | + +## First Login + +Default account: + +| Username | Password | +| --- | --- | +| `root` | `123456` | + +Please change the default password immediately after logging in for the first time. ## Swagger -After logging in, open: +Access after logging into the management console: ```text http://localhost:3000/swagger/index.html ``` -Regenerate Swagger files locally: +Regenerate Swagger locally: ```bash go install github.com/swaggo/swag/cmd/swag@v1.16.4 cd openflare_server swag init -g main.go -o docs ``` + +The generated Swagger files are located in `openflare_server/docs`. diff --git a/docs/en/guide/upgrade.md b/docs/en/guide/upgrade.md index a6e0088c..325981b6 100644 --- a/docs/en/guide/upgrade.md +++ b/docs/en/guide/upgrade.md @@ -1,16 +1,29 @@ # Upgrade and Maintenance +You will learn: How to upgrade the Server and Agent, how to clean up observability data, and which verification commands to execute before and after maintenance. + +Before upgrading, it is recommended to confirm the current activated version, the latest Agent application result, and the database backup policy. Do not upgrade in production environments while configuration publishing, large-scale Agent reconnection, or database migrations are in progress. + ## Server Upgrade -Root users can check and upgrade stable Server releases from the console header. Manual binary upload is also supported. +Root users can check and upgrade the Server stable version from the top bar of the management console. Upgrades can also be confirmed and executed by uploading the Server binary. -Preview releases require manual selection. Stable releases are recommended for production. +To try a preview version, you can manually check the corresponding release. It is recommended to prioritize the stable version in production environments. + +After upgrading, confirm: + +```bash +docker compose ps +docker compose logs -n 100 openflare +``` + +If it is a source deployment, confirm that there are no database migration or startup errors in the logs after restarting the Server. ## Agent Upgrade -Agents follow stable releases by default. Preview upgrades must be triggered manually. +Node Agents follow stable versions by default for automatic updates. Preview upgrades must be triggered manually. -The install script can be re-run for reinstall or upgrade: +The installation script can be executed repeatedly to reinstall or upgrade the Agent: ```bash curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/install-agent.sh | bash -s -- \ @@ -18,30 +31,55 @@ curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/inst --agent-token YOUR_AGENT_TOKEN ``` +Note: Currently, the installation script will delete the entire installation directory during reinstallation, including the old `agent.json`, local state, cache data, and downloaded binaries. Please confirm that you still have a usable Token on hand before executing. + +After upgrading, confirm: + +```bash +systemctl status openflare-agent +journalctl -u openflare-agent -n 100 --no-pager +``` + ## Data Maintenance -The settings page controls observability cleanup: +The settings page of the management console can maintain the observability data automatic cleanup policy: -| Option | Description | +| Configuration Item | Description | | --- | --- | -| `DatabaseAutoCleanupEnabled` | Enable daily cleanup | -| `DatabaseAutoCleanupRetentionDays` | Retention days, minimum 1 | +| `DatabaseAutoCleanupEnabled` | Whether to enable daily automatic cleanup | +| `DatabaseAutoCleanupRetentionDays` | Automatic cleanup retention days, at least 1 day | -When enabled, Server cleans access logs, metric snapshots, and request reports at 03:00 every day. +Once enabled, the Server will clean up access logs, metric snapshots, and request reports at 3 AM every day. -## Validation Commands +## Common Verification Commands + +Server: ```bash cd openflare_server GOCACHE=/tmp/openflare-go-cache go test ./... ``` +Agent: + ```bash cd openflare_agent GOCACHE=/tmp/openflare-go-cache go test ./... ``` +Frontend: + ```bash cd openflare_server/web +pnpm lint +pnpm typecheck +pnpm test +pnpm build +``` + +Docs: + +```bash +cd docs pnpm build ``` diff --git a/docs/en/plan/Agent Unified OpenResty Binary Control Scheme.md b/docs/en/plan/Agent Unified OpenResty Binary Control Scheme.md new file mode 100644 index 00000000..01e85fce --- /dev/null +++ b/docs/en/plan/Agent Unified OpenResty Binary Control Scheme.md @@ -0,0 +1,84 @@ +# Agent Unified OpenResty Binary Control Scheme + +## Summary + +Unify the Agent running model as "write to the managed configuration file, then call the `openresty` binary to execute `-t`, reload, start/restart". Docker deployment no longer has the Agent control another OpenResty container, but instead provides an independent `ghcr.io/rain-kl/openflare-agent` image; this image is based on `openresty/openresty`, with the Agent controller and OpenResty binary built-in. + +## Key Changes + +- Agent runtime: + - Remove the DockerExecutor / Docker container management logic from the production path. + - Default to using `openresty` when `openresty_path` is not configured. + - Uniformly execute binary calls with `-c ` to avoid misreading the OpenResty default configuration. + - The apply flow is: backup -> write files -> `openresty -t -c ...` -> reload; if reload indicates it is not running, then start. + - restart uses `openresty -c ... -s quit` followed by `openresty -c ...` to start, keeping fault tolerance for missing PIDs. + +- Configurations and File Responsibilities: + - Keep parser compatibility for old fields `openresty_container_name`, `openresty_docker_image`, and `docker_binary`, but mark them as deprecated and no longer involved in control logic. + - Add `access_log_path`, defaulting to `data_dir/var/log/openflare/access.log`, and no longer placing access logs inside `conf.d`. + - Add `runtime_config_dir`, defaulting to `data_dir/etc/openflare`, where `pow_config.json` is written. + - `cert_dir` only writes certificate/key files; `lua_dir` only writes Lua code and static resources. + - Support splitting files before writing: certificate files go into `cert_dir`, and `pow_config.json` goes into `runtime_config_dir`. + +- Docker Agent Image: + - Add `openflare_agent/Dockerfile`, with the runtime image based on `openresty/openresty:alpine`. + - Defaults to `OPENFLARE_OPENRESTY_PATH=openresty` and `OPENFLARE_DATA_DIR=/data`. + - Expose `80`, `443`, and `18081`. + - Support mounting `/etc/openflare/agent.json`, and also support environment variable configurations. + - CI publishes independent multi-architecture images: `ghcr.io/rain-kl/openflare-agent:` and `latest`. + +- Agent Configuration Entry: + - Keep `-config` + `agent.json`. + - Add environment variable overrides/fallbacks: `OPENFLARE_SERVER_URL`, `OPENFLARE_AGENT_TOKEN`, `OPENFLARE_DISCOVERY_TOKEN`, `OPENFLARE_NODE_NAME`, `OPENFLARE_NODE_IP`, `OPENFLARE_DATA_DIR`, `OPENFLARE_OPENRESTY_PATH`, `OPENFLARE_HEARTBEAT_INTERVAL`, `OPENFLARE_REQUEST_TIMEOUT`, `OPENFLARE_OPENRESTY_OBSERVABILITY_PORT`. + - If the configuration file does not exist but environment variables are sufficient, the Agent can start directly; if both exist, environment variables override file values. + +- Scripts and Documentation: + - `install-agent.sh` becomes a local OpenResty deployment script, adding `--openresty-path` and automatically finding `openresty` when not passed. + - `uninstall-agent.sh` only uninstalls the Agent itself, and no longer deletes the Docker OpenResty container or image. + - Update architecture, development constraints, deployment instructions, Agent guide, configuration item reference, README, and old Docker control descriptions in English image documents. + +## Public Interfaces + +- Add Agent configuration fields: + - `access_log_path` + - `runtime_config_dir` + +- Deprecated but compatibly read: + - `openresty_container_name` + - `openresty_docker_image` + - `docker_binary` + +- Add Docker image: + - `ghcr.io/rain-kl/openflare-agent` + +- Target Docker execution method examples: + - Mount configuration file: `-v ./agent.json:/etc/openflare/agent.json` + - Or environment variables: `-e OPENFLARE_SERVER_URL=... -e OPENFLARE_AGENT_TOKEN=...` + +## Test Plan + +- `openflare_agent/internal/config`: + - Default `openresty_path` is `openresty`. + - Old Docker fields can be read but do not affect the executor. + - Environment variables can start the Agent without a configuration file and can override the configuration file. + - New default paths conform to responsibility boundaries. + +- `openflare_agent/internal/nginx`: + - Binary commands all include `-c `. + - Apply success, reload failure rollback, and start fallback when not running. + - `pow_config.json` is no longer written to `cert_dir` or `lua_dir`. + - Stale `cert_dir/pow_config.json` and `lua_dir/pow_config.json` will be cleaned up. + - access log is rendered to `access_log_path`. + - checksum can still uniformly include the main config, route config, certificates, and PoW config into comparisons. + +- Integration Regression: + - `cd openflare_agent && GOCACHE=/tmp/openflare-go-cache go test ./...` + - `cd openflare_server && GOCACHE=/tmp/openflare-go-cache go test ./...` + - Dockerfile build smoke test: build the Agent image and start it using env-only configuration to the executable stage. + +## Assumptions + +- Docker Agent image name is fixed as `ghcr.io/rain-kl/openflare-agent`. +- Old Docker control fields are compatibly preserved but are no longer a supported behavior. +- This phase does not modify Server APIs, does not modify database models, and does not introduce remote command capabilities. +- The OpenResty main configuration template continues to be generated by the Server; the Agent is only responsible for local path replacement, file landing, and binary control. diff --git a/docs/en/reference/api.md b/docs/en/reference/api.md index 2c3cb62d..98df8863 100644 --- a/docs/en/reference/api.md +++ b/docs/en/reference/api.md @@ -1,10 +1,12 @@ # API Conventions -Management API and Agent API both use JSON. +You will learn: The response structure, path conventions, authentication methods, and Swagger entry point for OpenFlare management and Agent APIs. -## Response Shape +Both the OpenFlare management APIs and Agent APIs use JSON. -Success and failure responses should include a clear `message`: +## Response Structure + +Both success and failure should return a clear `message`: ```json { @@ -14,31 +16,33 @@ Success and failure responses should include a clear `message`: } ``` -## Paths +## Path Conventions | Type | Convention | | --- | --- | -| Management API | Authenticated by management Session | +| Management API | Authenticated by management console Session | | Agent API | Fixed under `/api/agent/*` | -| Read-only endpoints | `GET` | -| Mutating endpoints | `POST` | +| Read-only API | Use `GET` | +| Mutation-type API | Use `POST` | ## Authentication -Management endpoints reuse the existing login, role, and Session system. +The management console continues to reuse the existing login, role, and Session system. -Agent requests use the node-specific `agent_token`. First-time registration can use a global `discovery_token`. The header is: +Official Agent requests uniformly use the node-exclusive `agent_token`; the first access can use the global `discovery_token`. The Agent request header is fixed as: ```http X-Agent-Token: ``` -Do not log full tokens. +Full Tokens must not be printed in the logs. ## Swagger -After logging in: +Accessible after logging into the management console: ```text /swagger/index.html ``` + +The Swagger files are located in `openflare_server/docs`, generated by `swag init`. diff --git a/docs/en/reference/cli.md b/docs/en/reference/cli.md index ef01ebab..c4c90996 100644 --- a/docs/en/reference/cli.md +++ b/docs/en/reference/cli.md @@ -1,7 +1,11 @@ # Commands and Scripts +You will learn: Common commands for starting, building, testing, installing, and uninstalling the OpenFlare Server, management console frontend, Agent, Swagger, and documentation site. + ## Server +Start from source: + ```bash cd openflare_server export SESSION_SECRET='replace-with-random-string' @@ -10,10 +14,14 @@ export LOG_LEVEL='info' go run . ``` +Specify listening port and log directory: + ```bash go run . --port 3000 --log-dir ./logs ``` +Test: + ```bash cd openflare_server GOCACHE=/tmp/openflare-go-cache go test ./... @@ -21,29 +29,48 @@ GOCACHE=/tmp/openflare-go-cache go test ./... ## Frontend +Development: + ```bash cd openflare_server/web pnpm install pnpm dev ``` +Build static artifacts: + ```bash cd openflare_server/web pnpm build ``` +Checks: + +```bash +cd openflare_server/web +pnpm lint +pnpm typecheck +pnpm test +``` + ## Agent +Run from source: + ```bash cd openflare_agent go run ./cmd/agent -config /path/to/agent.json ``` +Compile: + ```bash cd openflare_agent go build -o openflare-agent ./cmd/agent ``` +Test: + ```bash cd openflare_agent GOCACHE=/tmp/openflare-go-cache go test ./... @@ -62,3 +89,29 @@ curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/inst ```bash curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/uninstall-agent.sh | bash ``` + +## Swagger + +Regenerate Swagger documentation: + +```bash +go install github.com/swaggo/swag/cmd/swag@v1.16.4 +cd openflare_server +swag init -g main.go -o docs +``` + +## Docs + +Local preview: + +```bash +cd docs +pnpm dev +``` + +Build: + +```bash +cd docs +pnpm build +``` diff --git a/docs/en/reference/index.md b/docs/en/reference/index.md index f52df6ab..a143db5d 100644 --- a/docs/en/reference/index.md +++ b/docs/en/reference/index.md @@ -1,10 +1,12 @@ # Reference -This section collects stable runtime, API, and repository information for deployment, integration, and troubleshooting. +You will learn: What information belongs to stable reference materials, and where to look up configurations, commands, APIs, and the repository structure. + +This section collects stable information at the runtime, interface, and repository levels, suitable for quick lookups during deployment, joint debugging, and troubleshooting. | Page | Content | | --- | --- | -| [Configuration](./configuration.md) | Server environment variables, CLI flags, runtime options, and Agent config fields | -| [Commands and Scripts](./cli.md) | Startup, build, test, install, and uninstall commands | -| [API Conventions](./api.md) | Management API and Agent API response, auth, and path conventions | +| [Configuration Items](./configuration.md) | Server environment variables, command line parameters, runtime Options, and Agent configuration fields | +| [Commands and Scripts](./cli.md) | Common startup, build, test, install, and uninstall commands | +| [API Conventions](./api.md) | Response structure, authentication, and path conventions of management and Agent APIs | | [Repository Layout](./repository.md) | Responsibilities of `openflare_server`, `openflare_agent`, `openflare_server/web`, and `docs` | diff --git a/docs/en/reference/repository.md b/docs/en/reference/repository.md index d096f4bd..01c5a26e 100644 --- a/docs/en/reference/repository.md +++ b/docs/en/reference/repository.md @@ -1,32 +1,47 @@ # Repository Layout +You will learn: What the Server, Agent, frontend, scripts, and documentation directories in the OpenFlare repository are responsible for, and which layer to place your logic when contributing code. + | Path | Responsibility | | --- | --- | -| `openflare_server` | Gin + GORM + SQLite/PostgreSQL control plane | -| `openflare_server/web` | Next.js 15 App Router admin frontend, statically exported and served by Go Server | -| `openflare_agent` | Go Agent running on nodes | -| `scripts` | Agent install, uninstall, and helper scripts | -| `docs` | VitePress docs site, design baseline, development rules, deployment and configuration docs | +| `openflare_server` | Gin + GORM + SQLite/PostgreSQL monolithic control plane | +| `openflare_server/web` | Next.js 15 App Router management console frontend, statically exported and hosted by the Go Server | +| `openflare_agent` | Go monolithic Agent, running on the node side | +| `scripts` | Helper scripts such as Agent installation, uninstallation, etc. | +| `docs` | VitePress documentation site, design baseline, development constraints, deployment, and configuration documents | -## Server Layers +## Server Layering | Directory | Responsibility | | --- | --- | -| `controller/` | Parse input, call service, return response | -| `service/` | Business logic, validation, transactions, rendering | -| `model/` | Models, database versioning, migrations | +| `controller/` | Parameter parsing, calling services, returning responses | +| `service/` | Business logic, verification, transaction orchestration, configuration rendering | +| `model/` | Model definition, database version, and migration | | `router/` | Route registration | -| `middleware/` | Auth, authorization, rate limiting, cross-cutting logic | -| `common/` | Configuration, global state, initialization | -| `utils/` | Pure helpers | +| `middleware/` | Auth, authorization, rate limiting, and other cross-cutting logic | +| `common/` | Configuration, global state, and initialization entry points | +| `utils/` | Pure utility functions and general helpers | -## Frontend Layers +## Agent Modules + +| Module | Responsibility | +| --- | --- | +| `config` | Configuration reading and default values | +| `heartbeat` | Heartbeat and version summary judgment | +| `sync` | Configuration pulling and application orchestration | +| `nginx` / `openresty` | OpenResty file writing, verification, reload, startup, and rollback | +| `state` | Local state and observability supplementary reporting buffer | +| `httpclient` | Server communication | +| `protocol` | Agent API protocol types | +| `internal/updater` | Agent self-updating | + +## Frontend Layering | Directory | Responsibility | | --- | --- | -| `app/` | Routes, layouts, page composition | -| `features/` | Business-domain modules | -| `components/` | Cross-feature reusable components | -| `lib/` | API client, env, utilities, constants | -| `store/` | Small cross-page UI state | -| `types/` | Shared types | +| `app/` | Routes, layouts, page assembly | +| `features/` | Organize modules by business domains | +| `components/` | Reuse components across features | +| `lib/` | Request client, environment variables, utility functions, constants | +| `store/` | A small amount of cross-page UI state | +| `types/` | Shared type definitions |