# Full-Stack Development

> Cordium documentation. Canonical page: <https://octelium.com/docs/cordium/latest/examples/dev/fullstack>.

This example sets up a complete, ready-to-code development environment for a full-stack application: a Go API and a React frontend built with Vite in the same repository, backed by the team's staging PostgreSQL database. Every developer gets their own persistent *Workspace* in which both dev servers are already running when it starts, the frontend and the API are available over HTTPS in the browser, and the staging database is accessible without any password.

## The Template

The *Template* uses the official Go image and adds Node.js via a [devcontainer feature](https://octelium.com/docs/cordium/latest/workspaces/image.md#devcontainer-features). The repository is cloned with each developer's own GitHub account via the `github` *GitProvider* of the `storefront` *Space* (read more [here](https://octelium.com/docs/cordium/latest/workspaces/secrets.md#gitproviders)):

```yaml
spec:
  image:
    registry:
      url: golang:1.26-bookworm
  repository:
    url: https://github.com/acme-corp/storefront
  gitProvider: github.storefront.cordium
  runtime:
    devcontainers:
      features:
        - reference: ghcr.io/devcontainers/features/node:1
          options:
            - key: version
              value: "24"
        - reference: ghcr.io/devcontainers/features/github-cli:1
    envVars:
      - key: DATABASE_URL
        value: postgres://pg-staging.payments:5432/storefront
      - key: VITE_API_URL
        value: http://localhost:8080
    tasks:
      - name: dependencies
        type: ON_CREATE
        workingDir: /workspace/repo
        onFailure: ON_FAILURE_ABORT
        run: |
          (cd api && go mod download)
          (cd web && npm ci)
      - name: api
        type: POST_START
        workingDir: /workspace/repo/api
        isBackground: true
        run: |
          timeout 120 sh -c 'until getent hosts pg-staging.payments > /dev/null; do sleep 2; done'
          go run ./cmd/server
      - name: web
        type: POST_START
        workingDir: /workspace/repo/web
        isBackground: true
        run: npm run dev -- --host 0.0.0.0 --port 5173
  limit:
    cpu:
      millicores: 4000
    memory:
      megabytes: 8192
    storage:
      megabytes: 30000
```

Here are a few notes about this *Template*:

- The `api` task waits until the name of the `pg-staging.payments` Octelium *Service* resolves, since the *Workspace* connects to the *Cluster* at the beginning of the `POST_START` phase (read more [here](https://octelium.com/docs/cordium/latest/workspaces/runtime.md#task-order)). The database password is injected by Octelium, which is why `DATABASE_URL` contains none (read more [here](https://octelium.com/docs/cordium/latest/workspaces/secretless.md)).
- Both dev servers run as background tasks, which means that the *Workspace* becomes `RUNNING` without waiting for them, and that they keep running for as long as the *Workspace* runs. Their output is available in the *Workspace*'s logs.
- The dev servers listen on `0.0.0.0` so that they can be reached through the portal (read more [here](https://octelium.com/docs/cordium/latest/workspaces/applications.md)).

Since the repository is cloned with each developer's own account, this *Template* is not pre-built. Instead, each developer's *Workspace* is persistent, which means that the dependencies are only installed on its first run.

```bash
cordium create template fullstack.storefront.cordium --file fullstack.yaml
```

## Creating a Workspace

Applications are specific to each *Workspace*. Create a persistent *Workspace* with the frontend as its default application and the API as a named one:

```bash
cordium create ws --template fullstack.storefront.cordium \
  --port web:5173:default \
  --port api:8080
```

Then, open the *Workspace*'s page in the web portal, click **Sign in to Git provider** to authorize GitHub, and start it. Once it is running, the frontend is available at `https://<WORKSPACE>.cordium.<DOMAIN>` and the API at `https://api_<WORKSPACE>.cordium.<DOMAIN>`, both authenticated with your Octelium identity.

## Developing

You can work from a browser terminal, or connect VS Code, Cursor, Zed or a JetBrains IDE over SSH (read more [here](https://octelium.com/docs/cordium/latest/use/ssh.md#remote-development-with-ides)):

```bash
octelium connect -d
cordium code <WORKSPACE>
```

Since Vite's dev server reloads on file changes, your edits are immediately visible in the browser. `git pull` and `git push` use your GitHub account through the *GitProvider*, while the `gh` CLI, which is installed by its devcontainer feature, can be authenticated separately via `gh auth login`.

## Sharing a Preview

When your branch is ready for review, share the frontend with the other *Members* of the `storefront` *Space* from the **Applications** panel of the *Workspace*'s page in the web portal, or via the SDKs. Your teammates can then open `https://web_<WORKSPACE>.cordium.<DOMAIN>` with their own identities while your *Workspace* is running (read more [here](https://octelium.com/docs/cordium/latest/workspaces/applications.md#sharing-applications)):

```go
if err := ws.SharePort(ctx, "web", cordium.ShareWithMembers); err != nil {
	return err
}
```

To share a preview with people who are not *Users* of your *Cluster*, such as a customer or a designer, serve it as a public Octelium *Service* instead (read more [here](https://octelium.com/docs/cordium/latest/examples/security/serving.md)).
