cicadel
Documentation

Application foundation

The application foundation covers DEV-01, DEV-02, DEV-03, DEV-05, DEV-06 and DEV-07: project/app scaffolding, settings, registration and lifecycle, routing, management commands, checks and local rebuild/restart. Its public APIs remain experimental. The separate reusable-package battery (DEV-04), database inspection/shell tools (DEV-08), and independent release validation retain their own acceptance criteria in the inventory.

Projects and upgrades

cicadel startproject DIRECTORY example.com/project creates an ordinary Go module, manage.go, typed project settings, explicit project/apps.go, root routes, compiled components, embedded CSS and request tests. startapp NAME [DIRECTORY] creates model, view, route, migration and test files. Names and module paths are validated before writing. Existing destinations are never intentionally replaced. startpackage is the independently distributable-app scaffold.

Keep models in apps/notes/models.go, split them into multiple files in that Go package, or move them to apps/notes/models/ with package models and import that package explicitly. Do not keep duplicate model declarations in both layouts. There is no runtime discovery. Register owned models with ModelOf in the app’s Models() list. makemigrations and generatequeries consume that same registry. Handwritten SQL also belongs to recorded history with reviewed historical metadata. Neither startup nor reload calls AutoMigrate or applies migrations.

For upgrades, pin the intended framework version with go get, run go mod tidy, read release notes, and generate a reference project in a new directory. Compare it with your project and merge deliberate changes. Generation does not rewrite existing settings, models, components or migration history. Run the matching go tool cicadel ui build, ui check --json and project tests before deployment. See the upgrade policy and model migrations.

Configuration and registration

Settings precedence is defaults, typed project assignments, then explicit environment overrides. Every operational field has a documented override in operations. Invalid values fail without printing their contents. settings.LoadWith accepts an injected lookup for tests; it never changes the process environment. Loaded and constructed applications own their allowed-host slices. Settings formatting and structured logging redact DatabaseURL; directly logging that field or serializing arbitrary application secrets bypasses this protection.

Package settings are ordinary typed constructor options, passed explicitly from project/apps.go. Validate them in the constructor or a registered check; do not introduce a shared untyped registry or mutate another app’s settings. A new factory call must allocate fresh lifecycle state for each test or application.

App descriptors are copied at construction. Registration rejects duplicate labels, missing dependencies, cycles, incompatible manifest versions and contribution collisions. Dependency ordering is stable. Startup runs checks before acquiring resources. Successful hooks and a failing hook’s returned cleanup run in reverse order on failure. Successful startup is idempotent; closed applications cannot restart. Close follows HTTP drain and attempts every cleanup even when one fails. Hooks must honor context deadlines and must not recursively call Start or Close.

Routes use typed urls.Route values and standard HTTP handlers. urls.Include applies namespaces and prefixes; reversal validates parameters. App middleware wraps only that app’s routes, in declaration order. See the application API and installable lifecycle contracts.

Management commands

go run manage.go help lists built-in, project and namespaced app commands in sorted order. help COMMAND or COMMAND --help shows its description without running checks, startup hooks or the command. Add descriptions through App.CommandHelp or Manager.CommandHelp; descriptions must reference registered commands. Project names are lowercase identifiers with optional hyphens and underscores; app commands remain app:command. Collisions are errors.

Runtime commands execute after checks/startup and receive cleanup on success or failure. Explicit App.BuildCommands run without database validation or runtime hooks. Constructors and the generated project’s Build function still run before Manager.Run; a project that opens a database during construction needs its configuration even for help. Offline tools should use a separate construction path when that distinction matters.

Custom commands receive an unmodified argument slice and context. Use Go’s flag.NewFlagSet(name, flag.ContinueOnError), choose an explicit output writer, and return management.UsageError{Err: err} for invalid flags or arguments. Handle flag.ErrHelp as success. Return ordinary errors for execution failures. Do not call os.Exit inside commands, because it bypasses lifecycle cleanup.

management.ExitCode(err) defines 0 for success/help, 2 for usage errors, 130 for context cancellation, and 1 for execution/configuration failure. Generated manage.go and the framework CLI use it. Existing entry points can adopt the same helper. The exit status of go run itself is Go’s launcher status; build an executable to observe the application’s exact status directly.

Structured system and deployment checks

Legacy App.Checks continue to return errors. New App.SystemChecks register SystemCheck{Deployment: bool, Run: func(context.Context) []CheckMessage}. Each message has a local ID, severity (info, warning, error), concise Message and optional Hint. IDs must be lowercase contribution identifiers and unique within one check invocation. The framework qualifies them as app:check:id and rejects invalid results. Diagnostics are ordered by app dependencies, sorted check names, and the check’s returned message order. Keep messages and hints free of secrets.

Ordinary startup fails on error diagnostics; warnings and information do not block startup. Deployment-only checks run only on explicit request. Checks must be read-only, must honor cancellation, and must not start background services.

text
go run manage.go check
go run manage.go check --deploy --fail-level warning
go run manage.go check --deploy --json

--deploy additionally checks debug mode, secure cookies and explicit allowed hosts, and runs package deployment checks. --json emits a diagnostic array, including on check failure. --fail-level selects the minimum failing severity; it defaults to error. Database provider requirements are included in management checks. These checks cannot certify a reverse proxy, external TLS, backups or production infrastructure; those remain deployment responsibilities.

Development rebuild and restart

Install the matching CLI and the pinned CSS compiler once, then run:

text
go tool cicadel ui css install
CICADEL_DEBUG=true CICADEL_SECURE_COOKIES=false go tool cicadel dev

dev --dir DIRECTORY --interval 300ms --shutdown-timeout 10s watches a project containing go.mod and manage.go. It compiles components and configured CSS, builds an executable outside the project, and runs it with runserver. The same project configuration and environment apply to every generation. It does not install build tools implicitly. Applications using another CSS system retain their own build process when no ui.css.json is configured.

Content hashes detect creation, deletion and same-size changes, including embedded assets. Two stable observations debounce edits. A source change during a successful build causes another build before that binary is served. A failed build reports compiler/source diagnostics and leaves the working server alive. Fixing the source triggers a new build. The old server receives an interrupt only after a replacement build succeeds; it is reaped before the replacement starts. Shutdown escalates to kill after the configured timeout. Interrupt and SIGTERM stop the supervisor and its child. A server that exits, including on a port conflict, returns an error with its output instead of repeatedly spawning failing processes.

Hidden files/directories, bin, dist, vendor, node_modules and nested Go modules are excluded. The project root is resolved to its real path; symlinks within the source tree are rejected with a diagnostic. Put generated runtime logs and artifacts in an excluded output directory. Changes to another module or environment require restarting the supervisor. This is an executable restart workflow; it does not preserve process memory, inject browser refresh scripts or provide in-process hot replacement. Production remains go build and ordinary process supervision.

Acceptance evidence

  • settings: every operational override, malformed-value secrecy, copied host configuration, redacted formatted/structured diagnostics and fuzz boundaries.
  • Root application tests: route composition, dependency ordering, descriptor isolation, partial-start cleanup, cancellation, readiness, HTTP shutdown and structured check validation/deployment selection.
  • management: command collisions, offline/runtime lifecycle, deterministic help, check flags, severity thresholds, usage status and cancellation status.
  • internal/devserver: real executable rebuild, continued HTTP service after a compiler failure, recovery after fixing source, content-hash boundaries and forced shutdown/reaping of an unresponsive child.
  • internal/scaffold: generated project/app tests and an outside-source-tree executable exercise help, JSON checks, deployment rejection and exact exit codes; existing generated-consumer tests verify component and package integration.

The applicable repository workflows verify generated files, PostgreSQL integration, race checks, vet, fuzz targets, vulnerability scans and builds, including nested modules. External security review and beta adoption are not claimed by these tests.

Local verification on 2026-11-02 used Go 1.26.10 and PostgreSQL 18.4. The required commands from ci.yml, accounts.yml, formsets.yml and migration-installables.yml passed, including strict PostgreSQL/race coverage, all eight configured fuzz runs, generated-source checks, nested-module vet and vulnerability scans. Release CLI builds passed for Linux and macOS on amd64 and arm64. The root suite was rerun after the final watcher fixes. These results cover local checks; they do not claim an external review or a published release.

↑

Type to search this version.