# Cicadel dev: complete framework documentation Framework philosophy, implementation reports and contributor material. This is separate from the application-development guides. Source: development checkout. --- Source: `PLAN.md` Markdown: https://cicadel.fauzaanu.com/en/dev/sources/PLAN.md # Cicadel framework plan **Priority (2026-11-12):** the [Active DX milestone working group](#active-dx-milestone-working-group-lessonfuse-driven-highest-priority) comes first, then installable applications. Background (2026-11-10): a ready, released core comes first; see the [readiness checklist](https://cicadel.fauzaanu.com/en/dev/sources/README.md#readiness-checklist) and [AGENTS.md](https://github.com/fauzaanu/cicadel/blob/main/AGENTS.md). **Scope update:** [batteries.md](https://cicadel.fauzaanu.com/en/dev/sources/batteries.md) is the authoritative long-term battery inventory and support policy. Checked items below record bounded foundation work, not complete Django-equivalent batteries. Model-generated PostgreSQL migrations now have a verified experimental installable; remaining package-system contracts and public release work remain separate. ## 1. Product direction Build a Go web framework that helps a Django developer become productive without first designing a framework of their own. Preserve familiar project organization, route configuration, settings, and model-centered development while keeping Go code explicit and understandable. The first release should support a conventional server-rendered, database-backed application. JSON responses belong in the core HTTP layer, but a full API toolkit is a later feature. Success means a developer can create a project, add an app, define a model, apply a migration, register a route, and render a page by following one coherent tutorial. Deployment should produce a conventional Go executable with documented configuration and database requirements. The checklist tracks implemented and verified work. Released APIs follow the [stability guarantee](https://cicadel.fauzaanu.com/en/dev/releases/releases/index.md#stability-guarantee). ## 2. Design principles - Put familiar concepts in familiar places: settings, URLs, apps, models, views, templates, and management commands. - Favor explicit registration and dependency injection over runtime discovery, global mutable state, or import side effects. - Build on standard Go HTTP interfaces so existing middleware and tooling can integrate. - Choose one mature ORM for the first release. Expose its capabilities directly, adding thin framework integration only where it improves the application workflow. - Treat schema migrations as versioned, reviewable changes. Do not silently mutate production schemas at startup. - Establish secure defaults and clear errors before adding convenience features. - Build reusable, composable UI components inspired by React and Django Cotton: explicit props, children, named slots and isolated scope. Do not adopt Django’s template language or inheritance system. - Measure performance against representative workloads and preserve time for documentation and maintainability. ## 3. Architecture and ownership | Area | Cicadel owns | Integration boundary | | --- | --- | --- | | Application | Startup, app registration, dependency wiring, shutdown | Explicit composition; no required global application | | Settings | Typed configuration contract, loading, validation | Environment and caller-provided values; secrets excluded from logs | | URLs | App route inclusion, namespacing, names and reversal | Standard HTTP handlers; router choice validated in a prototype | | HTTP | Response helpers, errors, middleware composition | Standard request contexts, cancellation, and HTTP interfaces | | Database | Connection lifecycle, configuration, command integration | Selected ORM owns querying, relationships, and transactions | | Migrations | App discovery through registration, ordering, CLI workflow | Chosen migration engine owns execution history and locking | | Component UI | Component contracts, composition, namespaces, compilation and rendering | React/Cotton-inspired Go server rendering with contextual escaping; existing `html/template` is a temporary prototype | | Static assets | Development serving and production asset lookup | Embedded assets or external serving, with explicit configuration | | CLI | Project/app scaffolding and management commands | Build-time Go code and subprocesses with clear errors | | Security | Sessions, CSRF integration, security defaults | Established cryptographic primitives and reviewed dependencies | | Testing | App construction helpers and request/database fixtures | Standard Go tests and HTTP test utilities | | Operations | Health hooks, logs, graceful shutdown, observability hooks | Standard deployment and telemetry integrations | Framework source organization can differ from generated application organization. The familiar layout is a contract with application developers, not a requirement to force all framework internals into Django-shaped files. ## 4. Implementation checklist ### Validate the foundation Resolve the choices that affect the rest of the framework before committing to public APIs. - [x] Write short architecture decisions for the supported Go version, module layout, HTTP routing, settings, ORM, migration tooling, and initial database support. - [x] Evaluate mature Go ORM candidates using maintenance activity, documentation, releases, licensing, transaction support, relationships, context cancellation, pooling, migration compatibility, testability, and direct access to advanced queries. - [x] Prototype a related-model query, transaction rollback, pagination, a constraint violation, and migration execution against the leading ORM candidate. - [x] Start database validation with PostgreSQL. PostgreSQL is the only supported and planned backend; other databases are excluded. - [x] Define the generated project layout and public/private package boundaries. - [x] Specify benchmark workloads and an initial threat model covering configuration, HTTP input, templates, sessions, and database access. **Done when:** architecture decisions explain the choices and tradeoffs, and a small prototype proves the ORM and migration workflow. Do not build a generic multi-ORM abstraction. ### A complete request-to-database-to-page path Deliver the smallest framework that can run a real example application. - [x] Implement explicit application construction, app registration, startup validation, and graceful shutdown. - [x] Load typed settings with documented precedence: defaults, project configuration, then explicit environment overrides. - [x] Support root and app `urls.go` files, HTTP method routing, path parameters, route names, and duplicate-route diagnostics. - [x] Provide HTML, JSON, redirect, and error response helpers, with request contexts passed through database operations. - [x] Integrate ORM connection setup, cleanup, transactions, and explicit migration commands. - [x] Implement namespaced template lookup and project overrides using `html/template`. - [x] Build an articles example with list and detail pages backed by related database records. - [x] Add tests for request routing, configuration failures, database integration, template escaping, and shutdown behavior. **Done when:** the example starts from an empty database using documented commands, applies migrations, serves database-backed HTML and JSON, and builds into a Go executable. This is an internal milestone, not yet a production-ready release. ### The Django-familiar development workflow Make starting and growing an application consistent. - [x] Add a `cicadel` CLI for `startproject` and `startapp`. - [x] Define the generated `manage.go` entry point and commands for development serving, configuration checks, and migrations. - [x] Keep production builds on standard Go commands; define a development reload approach separately. - [x] Add named URL reversal with namespaces and explicit errors for missing or invalid parameters. - [x] Define middleware order and app initialization order, with diagnostics for dependency cycles. - [x] Add development static-file serving, embedded-template support, and a documented production asset strategy. - [x] Make development errors useful while ensuring production responses do not expose stack traces or secrets. - [x] Write the first complete tutorial and a Django-to-Cicadel concept guide. **Done when:** a new developer can scaffold an app and complete the tutorial without modifying framework internals. CI builds and runs the generated project to catch scaffold drift. ### Safe interactive applications Support browser forms and authenticated workflows before claiming production readiness. - [x] Establish request size limits, parsing rules, validation errors, and reusable form handling without assuming a Django-style metaclass system. - [x] Define sessions, secure cookie defaults, rotation, expiry, logout invalidation, and storage boundaries. - [x] Implement CSRF protection for cookie-authenticated state changes and document its middleware requirements. - [x] Add authentication and authorization primitives using established password hashing and explicit permission checks. - [x] Define redirect validation, proxy trust, host validation, and deployment-dependent security settings. - [x] Document ORM parameterization and unsafe raw-query boundaries, template trusted-content escape hatches, and file-upload limits. - [x] Extend the example with sign-in and authorized create/edit actions, including validation errors. - [x] Test unauthorized access, CSRF rejection, session rotation, escaping, and rollback on failed writes. **Done when:** the example supports authenticated edits, security behavior is documented and tested, and a focused security review has resolved release-blocking issues. ### Implement composable component UI The earlier template-definition prototype does not complete the intended engine. [The component UI design](https://cicadel.fauzaanu.com/en/dev/topics/component-ui/index.md) supersedes the earlier decision to retain Go template syntax as the public UI model. - [x] Record React/Django Cotton component composition as the UI direction, independently of Django backend conventions. - [x] Specify and implement component authoring/compiler contracts: explicit typed props, children, named slots, isolated scope, nesting and reusable layouts. - [x] Implement safe attribute merging, contextual escaping and explicit trusted-content boundaries across components and slots. - [x] Integrate package namespaces, overrides, component libraries, embedded assets, source diagnostics and a development regenerate/restart workflow. - [x] Define concurrent rendering, cancellation, cache isolation and production compilation/validation behavior. - [x] Convert scaffolding, articles, forms and catalog/admin to the component engine and publish a prototype migration guide. - [x] Complete the detailed acceptance checklist in docs/component-ui.md with functional, security and integration tests. - [x] Keep accessible form labels/errors in the existing examples and exclude native i18n/l10n; carry those requirements into the component system. **Done when:** a newly generated app composes reusable components and an external component library with typed props, children and named slots; escaping, isolation, diagnostics and production rendering are verified. The generated-consumer test and component verification record provide completion evidence; legacy template tests remain compatibility coverage. ### Production reliability and performance Make operational behavior predictable and measure the original performance motivation. - [x] Add structured logging hooks, request IDs, health/readiness hooks, and optional tracing/metrics integration. - [x] Document HTTP timeouts, database pool limits, cancellation, shutdown deadlines, and reverse-proxy configuration. - [x] Verify migration locking, partial-failure behavior, and coordination across multiple application instances. Document database backup and forward-repair procedures. - [x] Run unit and integration suites, race checks, dependency vulnerability checks, and targeted fuzzing of request/configuration boundaries in CI. - [x] Benchmark routing, middleware, ORM reads/writes, and rendered responses; report latency distributions, throughput, allocations, and error rates under load. - [x] Compare a minimal Go HTTP baseline and, where useful, an equivalent Django application with matched database, queries, hardware, workload, and deployment conditions. Publish versions and methodology alongside results. - [x] Exercise deployment from a clean build, including assets, migrations, configuration, and graceful termination. **Done when:** deployment is reproducible, operational limits are documented, and measured results identify acceptable overhead and remaining bottlenecks. Performance targets should be set from the baseline, not invented in advance. ### Public beta and stable release Validate the framework through more than its own demonstration app. - [x] Build a second application with different relationships and permissions to uncover assumptions in the first example. - [x] Publish current API documentation, tutorials, a changelog, and development policy. - [x] Establish semantic versioning, deprecation policy, release automation, and a private security-reporting process. - [x] ~~Obtain an independent security review~~ — not a release gate (owner decision 2026-11-10). - [x] Settle the public API surface for release: defined by the [stability guarantee](https://cicadel.fauzaanu.com/en/dev/releases/releases/index.md#stability-guarantee). An external beta period is not a release gate (owner decision 2026-11-10). - [x] Freeze the initial stable scope (v0.1.0) and document unsupported features and database limitations ([releases](https://cicadel.fauzaanu.com/en/dev/releases/releases/index.md)). - [ ] Close the open core gaps in the [readiness checklist](https://cicadel.fauzaanu.com/en/dev/sources/README.md#readiness-checklist), releasing each one. **Done when:** independent projects can follow the documented workflow, critical issues are resolved, and public contracts have enough evidence to support a stable release. ## Active DX milestone working group (Lessonfuse-driven): highest priority **Added 2026-11-12. Priority: above installable applications.** Lessonfuse, a production Django SaaS, is being ported to Cicadel. Each gap below was confirmed in Cicadel source during porting. Lessonfuse implements a local workaround first, under `internal/…` and marked with `// DX-nn`. Cicadel then ships the general feature, and Lessonfuse replaces its local copy. Each item is done when it is released with docs and tests, and Lessonfuse has removed its workaround. Port plan: `lessonfuse_reboot_cicadel/PLAN.md` §3. - [ ] **DX-01** Social and OIDC login (Google first), plus an extensible user model or profile hook. Today `contrib/accounts` has a fixed `accounts_users` table with bcrypt passwords only. - [ ] **DX-02** HTML `RequireLogin` that redirects to the login page with a safe `?next=`. Today both variants return 401. **Cicadel side done (v0.2.7):** `Browser.LoginRequired(loginURL)` with safe `next`, htmx `HX-Redirect`, sign-in returns to `next` (`contrib/accounts/browser.go`, `browser_test.go` on PostgreSQL). Open: Lessonfuse removes `internal/auth/guards.go` RequireLogin. - [ ] **DX-03** Configurable body limits for authenticated routes. `Browser.Middleware` caps every wrapped body at 8 KiB, which breaks large forms and uploads. **Cicadel side done (v0.2.7):** the 8 KiB cap is gone from `Browser.Middleware`; account pages keep 8 KiB (`limitAccountForms`). Open: Lessonfuse can return to `Browser.Middleware` only after DX-01 (it uses its own Google users table). Remaining Cicadel gap: a plain (non-htmx) multipart form under `Browser.Middleware` fails CSRF unless `upload.Middleware` runs outside CSRF or the form sends `X-CSRF-Token` — CSRF does not parse multipart bodies. - [ ] **DX-04** HTML error-page hooks for 400, 403, 404, 500 and CSRF failure, plus panic recovery that renders a page. Today these return plain text. **Cicadel side done (v0.2.7):** `errorpages.Middleware` (pages for plain-text 4xx/5xx incl. router 404/405 and CSRF, panic → 500 page, `Report` hook, htmx `cicadel:error` event), scaffolded `project/errors.go` + `errors.templ` (`errorpages/errorpages_test.go`, generated-project 404 test). Open: Lessonfuse replaces `internal/errorsui` Middleware with `Options.Page` + `Report` (its feedback form stays app code). - [ ] **DX-05** Redis cache backend for `cache.Backend`, and optionally a Redis session store. - [ ] **DX-06** S3-compatible storage: SigV4, nested keys, presigned browser URLs, public and private buckets. Today keys must be flat, there is no S3 support, and there is no URL method. - [ ] **DX-07** River integration: a `worker` management command, periodic or cron jobs, workers registered per app through `App`, queue priorities, a test backend, and an enqueue pattern for post-commit `InsertTx`. - [ ] **DX-08** htmx response helpers: `HX-Trigger`, `HX-Redirect`, `HX-Location`, `HX-Retarget`, `HX-Reswap`, `HX-Refresh` and out-of-band swaps. Also wire the CSRF header for htmx requests by default. **Cicadel side done (v0.2.7):** `htmx.Trigger`/`TriggerDetail`/`Redirect`/`Location`/`Refresh`/`Retarget`/`Reswap`/`Reselect`/`PushURL`/`ReplaceURL`/`CSRFHeaders`; `layout.Props.CSRFToken` sends `X-CSRF-Token` on htmx requests; OOB swaps documented with `ui.Group` + `hx-swap-oob`. Open: Lessonfuse replaces `internal/hx`. - [ ] **DX-09** Escape hatches in the component compiler, without weakening contextual escaping: - trusted SVG and icon components - a typed or sanitised `style` value (dynamic widths, background images) - a documented pattern for page scripts and data islands under the default CSP - [ ] **DX-10** `layout.Page` support for `lang` and `dir`, so RTL (Dhivehi/Thaana) pages work. **Cicadel side done (v0.2.7):** `layout.Props.Lang`/`Dir` (validated; `ui/layout/layout_test.go`). Open: Lessonfuse adopts it. - [ ] **DX-11** Response helpers for file downloads, attachments and streaming: Content-Disposition, `ServeContent`, streamed generation. - [ ] **DX-12** Money and decimal type mapped to `numeric(p,s)`. Typed JSONB, UUID and `bigint[]` field types that work end to end in models, querygen and migrations without per-project `CustomTypes` boilerplate. - [ ] **DX-13** Staff and superuser flags, plus superuser impersonation ("login as") with an audit trail. - [ ] **DX-14** Rate-limiting middleware backed by the cache (fixed or sliding window, per user or IP). - [ ] **DX-15** URL reversal from inside templ components, via the request context. - [ ] **DX-16** Wider migration support: partial unique indexes, deferrable unique constraints, GIN indexes and expression defaults. - [ ] **DX-17** Fixtures and seed data: `loaddata`/`dumpdata` equivalents, plus test factories. - [ ] **DX-18** `.env` loading for development. - [ ] **DX-19** Static pipeline that rewrites `url()` references inside CSS to hashed URLs (fonts, icons). - [ ] **DX-20** Error-tracking integration recipe (Sentry and OTel) for the web process and job workers. - [ ] **DX-21** `apptest` additions: a CSRF-token helper and a jobs test backend. - [ ] **DX-22** Deployment recipe for a web process, a worker process and a pre-deploy migrate step (Railway as the worked example). - [ ] **DX-23** Per-route write-timeout override for long-running handlers (LLM chat, document generation). - [ ] **DX-24** Document-generation contrib candidates: DOCX template rendering (placeholders split across runs), XLSX via excelize, HTML→PDF via headless Chromium. - [ ] **DX-25** `startproject`/`startapp` scaffolds emit Go that is not gofmt-formatted (one-line import groups, compressed bodies). Generated projects fail a `gofmt -l` CI gate until reformatted. **Cicadel side done (v0.2.7):** `startproject`/`startapp` run `go/format`; `TestGeneratedProject` asserts `gofmt -l` is empty. - [ ] **DX-26** Package settings can bind conventional environment names. Today every tagged field reads `CICADEL__`, so third-party credentials such as `OPENROUTER_API_KEY` or `SENTRY_DSN` cannot be read under their usual names without a custom lookup wrapper. - [ ] **DX-27** Cross-app foreign key cycles. Two apps that reference each other (a profile row pointing at a curriculum, a curriculum flag pointing at the profile) cannot both record a foreign key, because app migrations cannot depend on each other in a cycle. Django handles this by splitting the second constraint into a later migration; Cicadel needs an equivalent (for example a later-version reference to an app that depends on this one). - [ ] **DX-28** Defaults on custom column types. A model field mapped through migration `CustomTypes` (a `numeric(10,2)` money type, for example) cannot declare a database default: `makemigrations` fails with "custom field defaults require a historical schema declaration". Django writes `DEFAULT 0` for `DecimalField(default=0)`. Cicadel needs a way to record a literal default for a custom type (validated by the type, emitted in the generated SQL). - [ ] **DX-29** Per-route request body limits. `settings.MaxBodyBytes` wraps every request body before routing, so one upload route (a 10 MB image or PDF) forces the cap up for every form and JSON endpoint. Django separates `DATA_UPLOAD_MAX_MEMORY_SIZE` from file uploads. Cicadel needs a per-route (or per-content-type) override, for example a route option that raises the limit for a multipart upload while the global default stays small. **Cicadel side done (v0.2.7):** `bodylimit` package; `MaxBodyBytes` is an adjustable per-request default; `forms/upload` raises it to `Config.MaxBytes`; `bodylimit.Limit(n)` for other routes (`bodylimit/bodylimit_test.go` through a real Application). Open: Lessonfuse drops `internal/bodylimit` and its raised global cap. - [ ] **DX-30** Third-party embeds. The component compiler rejects `