# Installable applications

An installable app is a Go package that provides a `cicadel.App`: routes, commands, components, and optionally database migrations. Install its module, configure its factory, and register the returned app in your project.

First-party installable packages are core defaults composed through the same public contracts as your own packages. Standard scaffolding registers accounts and formsets and supplies migration and query-generation commands. Installing an additional third-party module with `go get` does not activate it.

## Ask your agent

```text
Read https://cicadel.fauzaanu.com/en/dev/topics/installable-apps/index.md.
Add [package and version] to my existing Cicadel application.
Inspect its constructor and required configuration, then register it in
project/apps.go without replacing existing apps. Check its dependencies and routes.
Review any database migrations before applying them. Run app checks and tests.
```

## Install a published package

Use the module path and version provided by the package author:

```sh
go get example.com/your-org/greetings@v0.1.0
```

`example.com/your-org/greetings` is a placeholder, not a published Cicadel package. The next section shows how to create a local package with this API.

In `project/apps.go`, import the package and add its constructor to your existing app list:

```go
package project

import (
    "os"
    greetings "example.com/your-org/greetings"
    "github.com/fauzaanu/cicadel"
    "github.com/fauzaanu/cicadel/contrib/formsets"
    "gorm.io/gorm"
)

func InstalledApps(_ *gorm.DB) ([]cicadel.App, error) {
    return []cicadel.App{
        formsets.App(),
        greetings.New(greetings.Options{
            Greeting: "Welcome",
            Output: os.Stdout,
        }),
    }, nil
}
```

This adds a package while retaining the standard formset registration; the project builder composes accounts. Preserve your other entries when adding it to an existing project. Database-backed factories can use the supplied `*gorm.DB`; follow that package's constructor signature.

## Create and use a local package

From an existing Cicadel project, scaffold a separate module beside it:

```sh
go tool cicadel startpackage ../greetings example.com/your-org/greetings greetings
cd ../greetings
go get github.com/fauzaanu/cicadel@main
go mod tidy
go test -race ./...
cd ../myapp
go mod edit -replace=example.com/your-org/greetings=../greetings
go get example.com/your-org/greetings@v0.1.0
```

Register it with the Go example above, then run:

```sh
go run manage.go apps
go run manage.go check
go run manage.go greetings:hello
# Welcome
go run manage.go runserver
```

`GET /greetings/` returns `{"greeting":"Welcome"}`. The package scaffold includes this route, a command, typed options, and tests. Use `startapp notes` instead when you only need an app inside one project.

## What a package returns

This small app exports one named route:

<!-- example: installable/apps/hello/app.go -->
```go
package hello

import (
    "net/http"
    "github.com/fauzaanu/cicadel"
    "github.com/fauzaanu/cicadel/response"
    "github.com/fauzaanu/cicadel/urls"
)

func New() cicadel.App {
    return cicadel.App{
        Name: "hello",
        Manifest: &cicadel.Manifest{
            Module: "example.com/hello",
            Version: "v0.1.0",
            API: cicadel.AppAPIVersion,
        },
        Routes: []urls.Route{
            urls.Path("GET", "/hello/", "hello:index",
                func(w http.ResponseWriter, r *http.Request) {
                    if err := response.JSON(w, http.StatusOK, map[string]string{"message": "Hello"}); err != nil {
                        response.Error(w, http.StatusInternalServerError)
                    }
                }),
        },
    }
}
```

`Name` owns the route and command namespace. Keep it stable across upgrades, especially when the app owns migration history. Go selects the module version; `Manifest.Version` describes the package's compatibility metadata.

## Add migrations and dependencies

For a package with PostgreSQL tables, embed recorded SQL migrations and declare the database requirement:

```go
//go:embed migrations/*.sql
var migrations embed.FS

func migrationFiles() (fs.FS, error) {
    return fs.Sub(migrations, "migrations")
}
```

Use the returned filesystem as `App.Migrations`, and set `Manifest.Providers` to `[]string{"postgres"}`. Import `embed` and `io/fs`. Handle the filesystem error in your factory, then run the host's `go run manage.go migrate` before serving requests. Follow [the migration guide](https://cicadel.fauzaanu.com/en/dev/topics/migrations/index.md) for generated model migrations.

If your package needs another installed app, declare it in `Manifest.Requires`:

```go
Requires: []cicadel.Requirement{
    {Name: "accounts", Version: cicadel.VersionRange{
        Min: "v1.0.0", Before: "v2.0.0",
    }},
},
```

These are example compatibility bounds, not a claim that an accounts v1 release exists. The host must register the dependency too. Missing or incompatible dependencies fail startup checks.

## Remove a project app

To disable an app, remove its constructor from `InstalledApps`. Remove unused imports and run `go mod tidy`. This does not delete tables or stored data; data removal must be a separate, deliberate operation.

For component exports, see [component libraries](https://cicadel.fauzaanu.com/en/dev/topics/component-ui/index.md#installable-libraries-and-overrides). For package lifecycle and compatibility details, see the [package authoring reference](https://cicadel.fauzaanu.com/en/dev/sources/skills/cicadel-installables/SKILL.md).
