Skip to content

Version 0.1.0

Release date: November 1, 2026

The first release of Anvil.

  • Panels with resources, forms, lists and cards, actions, widgets, navigation, global search and notifications – rendered on the server with htmx and Alpine.js under a strict Content Security Policy.
  • Security by default: public UUIDs only, tenant scoping, deny by default permissions with policies, a tamper-evident audit log, encrypted component tokens.
  • Access: tenants, roles and permissions in the database, two-factor authentication (TOTP), single sign-on with OpenID Connect and SAML.
  • Workflows with durations, deadline and forecast in working days, tasks and an inbox, tenant settings with optional four eyes release.
  • API for machine clients with tokens, signed requests, OpenAPI 3.1.
  • Documents with templates, signatures and retention.
  • Workflow schedules (ADR 0017): defaultDuration(), State::duration(), pausesClock(), goal(), expectedPath(), clockStartsIn(), deadline, forecast and risk per case, escalations whenOverdue() / whenAtRisk(), durations in the tenant settings, columns deadlineColumn(), forecastColumn(), stateDueColumn(), riskFilter(), a schedule on the detail page and in the API. Run the migrations.
  • Working calendar Anvil\Calendar\WorkingCalendar with GermanHolidays (all federal states) and $workingDays, $holidayProvider, $holidayRegion, $closedDays.
  • Phase 0 foundation:
    • Anvil\Data\Uuid: RFC 9562 version 7 UUIDs, stored as BINARY(16).
    • Anvil\Data\Model: enforced UUIDs, tenant scoping and auditing.
    • Anvil\Data\Entity: hides internal fields when serialized.
    • Anvil\Tenancy\TenantContext: fail-closed tenant context.
    • Anvil\Security\KeyRing: purpose bound keys derived via HKDF.
    • Tamper evident audit log with keyed hash chain and verifier.
    • Anvil\Security\Authorization\Gate: deny by default, permissions plus policies.
    • Component endpoint: encrypted, session bound component tokens, registry, dispatcher pipeline and controller.
  • Documentation skeleton and architecture decision records 0001 to 0010.
  • Phase 1:
    • Panels, pages, navigation and dashboard; routes generated from panels.
    • Resources with forms (text, textarea, select, checkbox list, toggle, date, password; sections and grids) and collections (table and cards, search, filters, sorting, pagination, delete, bulk delete).
    • Resource extension points and virtual fields.
    • Tenant memberships, tenant filter and switcher.
    • Database roles per tenant, user and role administration, escalation guard.
    • Profile page with password change and enforced password change.
    • Frontend assets with runtime theme tokens, dark mode and strict CSP.
    • Commands anvil:install, anvil:publish and make:anvil-resource.
    • English and German translations.
  • Phase 2:
    • BelongsTo field, relationship columns and filters, all based on UUIDs.
    • Related records on detail pages, creation with a verified parent.
    • Custom actions in the header and in rows, with confirmation and forms.
    • Change history from the audit log (permission <slug>.history).
    • Dashboard widgets (StatWidget).
    • Create, attach and detach in relation sections.
  • Forms:
    • Fields NumberInput (locale format, currency), Radio, TagsInput, Repeater, MarkdownEditor (server rendered preview), FileUpload; searchable BelongsTo with server side lookup.
    • Layouts Tabs, Wizard and collapsible sections.
  • Collections:
    • Filters TernaryFilter, DateRangeFilter, NumberRangeFilter and TextFilter (also on columns of joins and SQL expressions); reset filters.
    • * as wildcard in the search; columns with several query columns.
    • Custom bulk actions; toggleable columns and saved views per user.
    • CSV and Excel exports, large exports in the queue (codeigniter4/queue).
    • Widgets above lists (Resource::listWidgets()); StatWidget::fromList() follows search and filters.
    • Search: words joined with OR, phrases in quotes; also in the global search.
  • Panels:
    • Global search in the top bar; notification center.
    • Chart and table widgets (Chart.js loaded on demand).
    • Navigation badges, collapsible navigation groups, user menu items.
    • Related records of the detail page as tabs ($relationTabs) with the number of records; form tabs remember the open tab.
  • Files: attachments and file fields with a storage interface, content based type check and a virus scanner hook (ClamAV).
  • Extending: abstract Column, own views for fields and filters, Panel::scripts(), view overrides and language overrides documented.
  • Commands: generators make:anvil-field|column|filter|layout|page|widget|policy|panel, make:anvil-model, make:anvil-pivot; anvil:audit:verify, anvil:permissions.
  • Testing: Anvil\Test\InteractsWithAnvil and TestUploadedFile for application tests.
  • Documentation: reference for fields, collections, configuration and commands; extending guide; testing guide.
  • Single sign-on with OpenID Connect (ADFS 2016+): authorization code flow with PKCE, ID token validation via JWKS, roles from the groups claim (mapped in the role editor), users created at the first login, panels restricted to login methods (Panel::authMethods()), audit events auth.sso.login and auth.sso.failed; login view with SSO buttons; logout ends the session at the provider (RP-initiated logout).
  • SAML 2.0 single sign-on (onelogin/php-saml): signed assertions, request bound to the browser by a cross-site cookie, SP metadata endpoint, signed single logout, logout requests of the identity provider.
  • Two-factor authentication with TOTP (RFC 6238): setup with QR code on the profile page, recovery codes, second login step (Shield action TotpAction), replay protection, attempt limit, encrypted secrets, required per panel or globally, reset by administrators, audit events.
  • Audit key rotation: own audit key (anvil.auditKey), previous keys for verification, automatic audit.key_rotated entry, verifier enforces the key order; anvil:audit:generate-key.
  • Panel::permission(): permission to enter a panel at all (all routes), listed in the role editor; e.g. a back office next to a self service portal.
  • Tenant administration on the command line (anvil:tenant:*): create, rename, disable, delete (with all data, audit log kept), members and their roles; anvil:tenancy:enable/disable to switch multi tenancy with existing data. Generators always create a tenant_id column.
  • API module for machine clients (API):
    • API clients per tenant with explicit permissions, tokens (anv_<id>_<secret>, stored as SHA-256, several per client, expiry, revocation), optional IP allow list, signed requests with replay protection and own rate limits.
    • Request pipeline under /api/v1/: TLS, rate limits per IP and client, tenant, gate and audit actor of the client, validation with allow lists, Idempotency-Key, transactions, problem documents (RFC 9457), access log.
    • Resource endpoints (Resource::$api): list with filters, search, sort and encrypted cursors, show, create, PATCH of sent fields, delete, actions; representation from the form (UUIDs, ISO 8601, decimal strings).
    • Custom endpoints (ApiEndpoints, Config\Anvil::$apiEndpoints).
    • Resource “API clients” in Anvil\Access with escalation guard; tokens and signing secrets shown once; access log on the detail page.
    • anvil:api:review notifies owners of expiring and unused credentials.
    • OpenAPI 3.1 description: GET /api/v1/openapi.json and anvil:api:openapi.
    • Commands anvil:api:client:* and anvil:api:token:*.
  • Workflows (Workflows):
    • State machine per record: states (initial, locked, final), transitions with actors, guards, four eyes, reason, form, effects, optional steps.
    • Actors: permission, role, user, field, creator, resolvers of the application, “same as”, slots configured per tenant.
    • Definitions written in PHP produce versioned data; building blocks by key; validator; records keep their version (anvil:workflow:migrate).
    • Tenants: availability by operators, activation and configuration by administrators, release with four eyes; override permissions per workflow and per transition.
    • Panel: state, transitions and history on the detail page, locked records, page “Workflows”, stateColumn() and stateFilter().
    • Deadlines (remind, notify, run a transition) through anvil:tick.
    • API: state in the representation, GET …/transitions, POST …/transitions/{name}.
    • Commands anvil:workflow:list|enable|disable|check|migrate|diagram, anvil:tick.
  • Tasks and inbox (ADR 0013): decisions for the actors of a state, tasks in parallel with outcomes, forms, four eyes and due dates, automatic transitions (TaskCondition), claiming, reminders, tasks of applications (service('tasks')->assign()), inbox page with badge, tasks on the detail page.
  • Columns: computed values (state()), colours (color()), icons (icon()), a second line in the table (description()), relative dates (relative()), links to configured external systems (link(), Config\Anvil::$links, targets, noopener unless trusted) and to related records (linkToRecord()).
  • Collections: colour of records as table row and card (tone()); card areas badges, meta, rows and an own card view per collection.
  • Actions of records in rows and cards: buttons up to a limit per view (Collection::rowActions(), Action::primary()), the others in a “…” menu with delete last, everything in the menu on phones; actions with a form in rows (one dialog per action); link actions (Action::link(), Action::url()) with targets.
  • CountColumn: related records of a page loaded in one query and counted (scope and policies of their resource); Column::prepare().
  • UserSelect field: a person of the tenant (usernames of active members, UUIDs only) without access to the user administration.
  • Transition::inbox(false): side ways like “cancel” do not create decision tasks for their actors.
  • Config\Anvil::$policies: policies for every gate (panels, API, CLI).
  • Resource::detailComponents(): own components on the detail page.

The release went through a security review (OWASP Top 10, ISO 27001 controls). Fixed findings:

  • Security review (OWASP Top 10, ISO 27001), high findings fixed:
    • Remember-me tokens are no longer issued before the TOTP step; TOTP changes and password changes revoke all remember-me tokens.
    • Users linked to single sign-on only get into panels through their provider (no magic link or password login with outdated roles); without password login magic links are off.
    • Selects, relationship columns and select filters list records through the resource of the related model (scope, view permission, policies); global models need a resource or an explicit scope.
    • Bulk actions check the permission with policies for every record.
  • Medium findings:
    • The audit chain head is signed (HMAC with the current key, entry count checked): removed newest entries and an emptied log are detected, an old key cannot cut off a rotation; anvil:audit:rotate.
    • Security events in the audit log and the application log: logins, failed logins, logouts, magic links, denied requests and pages, refused tenant switches; bulk events throttled per IP.
    • Single sign-on routes are throttled (30 requests per minute and IP).
    • Lists, related lists and exports leave out records the policy does not let the user view.
    • Relations: creating from a relation and attaching need the update permission of the parent; moving or detaching records by foreign key needs their update permission.
    • User administration: users with more rights than the editor are out of reach (roles, deactivation, deletion, TOTP reset); username, active state and TOTP of users shared with other tenants change only with rights there.
    • Forced TOTP setup and password change close panels without profile page instead of opening them.
    • Wrong TOTP codes are counted per account: after ten the second factor is locked for 15 minutes.
    • linkByEmail links only verified addresses (email_verified or trustEmail).
  • Low findings and notes:
    • Activating and turning off TOTP need the current password.
    • SAML logout messages must be signed; the logout of the user menu is a POST.
    • Files belong to the resource class (no sharing between panels with the same slug), are deleted with their record and removed from the storage only after the commit (Transaction::afterCommit()/afterRollback()).
    • Exports: download only with the export permission in the panel of the export; queued exports run in the tenant of the export and fail if the user left it; no partial files; sandboxed downloads.
    • Rate limits on file and export downloads (Anvil\Security\RateLimit).
    • Super roles: only users with full access change or delete them; deleting a role needs all its permissions.
    • Links and redirects reject control characters; StatWidget::url() and user menu links accept only paths and http(s) URLs (SafeUrl).
    • Tenant switch with a token of the page; security headers on panel pages and endpoint answers.
    • make:anvil-resource skips columns with unusual names; anvil:install asks before giving an existing user full access (--promote).
    • CSV exports neutralise more formula prefixes (full width characters, |, %); more masked audit fields; format characters removed from file names; exact comparison of SSO groups; warning for policies with array records.
    • Documentation: production checklist, personal data in the audit log, where policies apply, Shield group fallback.
  • LIKE wildcards in search input are escaped (CodeIgniter does not).