This sample is a multi-user Next.js todo app that turns user feedback into live code changes. Better Auth and PostgreSQL provide accounts, private todo lists, and feedback storage. The first person to sign up becomes the administrator. From the admin page, that person can curate feedback, add instructions, and send the request to a Mastra coding agent that edits the app source, which the Next.js development server then hot-reloads.
To keep those edits from being served half-applied, the coding agent works in an isolated git worktree, not the files the dev server is serving. It makes and typechecks all its edits there; only a successful, compiling run is fast-forwarded into the live tree in a single step, so users see one atomic update instead of every intermediate keystroke (a multi-file change would otherwise flash broken states and flood the backlog with transient errors).
The Compose project separates the public production app from the live-editing environment:
appis a standalone Next.js production build with no source, agent, or admin UI.devcontains the source, Caddy, the Next.js dev server, and the Mastra agent.dbis shared PostgreSQL for auth, todos, and feedback.chatis the managed model used by the coding agent, declared as a top-levelmodels:entry; each cloud's env file selects an explicit model — z.ai GLM 5 on AWS Bedrock, Gemini 2.5 Flash on GCP Vertex AI.
The admin console is served by the agent server, not the Next.js app — it
lives outside the source tree the coding agent edits. Caddy routes /admin to
the agent server and everything else to Next.js, so the console stays usable to
recover the app even if a bad edit crashes the Next.js dev server.
Warning
This is a demo of agent-driven development, not a production software-update
design. The coding agent can change any file under todo-app/. The admin gate,
source boundary, and compile check reduce risk, but they are not a substitute
for code review, tests, signed artifacts, or a deployment approval process.
- Use a Defang CLI build that exposes
the resolved
DEFANG_PROVIDERandDEFANG_STACKCompose variables (added by DefangLabs/defang#2189); v3.12.0 does not include this support. - Authenticate with a cloud account that has managed LLMs: a GCP project with Vertex AI, or an AWS account with Bedrock model access.
- For local development, install Docker Desktop with Docker Model Runner enabled.
Start the live-editing environment, PostgreSQL, and the local model:
docker compose -f compose.dev.yaml up --buildThen open http://localhost:3000 and:
- Sign up. The first account becomes the administrator.
- Add a few todos.
- Use the feedback button in the lower-right corner.
- Open Admin, select feedback, add instructions, and choose Send to coding agent.
- Watch the run log. Successful edits appear in
todo-app/and hot-reload in the browser.
The local model is ai/qwen2.5-coder:7B-Q4_K_M. It is intentionally small so
the workflow can run on a laptop; use local development to test the loop, not to
judge the quality of the generated changes. The first run downloads the model.
Set these secrets before deploying:
defang config set POSTGRES_PASSWORD --random
defang config set BETTER_AUTH_SECRET --random
defang config set ADMIN_TOKEN --randomPOSTGRES_PASSWORDprotects the managed PostgreSQL database.BETTER_AUTH_SECRETsigns and encrypts authentication data. Keep it stable across deployments or existing sessions will be invalidated.ADMIN_TOKENis a break-glass password for the admin console. The console normally accepts your regular admin login (its session is validated directly against PostgreSQL, so it works even while the app is down); the token is the fallback for when no valid session is available.
The same Compose project deploys to either cloud; each cloud's env file selects
an explicit managed model (z.ai GLM 5 on AWS, Gemini 2.5 Flash on GCP). The
first deployment creates managed PostgreSQL and can take about 20 minutes.
Defang reports separate URLs for app and dev:
- Share the
appURL with normal users. - Use the
devURL for administration and live agent changes.
The dev service deliberately runs as one always-on instance so its working
tree survives idle periods. The app service remains a stateless production
build.
Cloud deployments share the one compose.yaml. After resolving the provider,
Defang automatically loads its non-secret interpolation file:
| Provider | Environment file | Publish permission |
|---|---|---|
aws |
.env.aws |
AdministratorAccess |
gcp |
.env.gcp |
roles/owner |
The two env files are the place to customize the managed model and other
cloud-specific scalar settings. Secrets still belong in defang config, never
in these committed files.
Self-publishing a full stack is administrator-equivalent. That permission is
attached only to dev, never the public app; scope it down before adapting
this demo for production.
The gcp env file selects gemini-2.5-flash on Vertex AI — a GA model that is
broadly available on-demand across regions with no special configuration.
Provide the target project when deploying:
export GCP_PROJECT_ID=your-gcp-project
defang compose up --stack gcpThe aws env file selects z.ai GLM 5 (zai.glm-5) on Bedrock. Enable model access
for it in the Bedrock console first. The aws stack selects us-east-1:
defang compose up --stack awsNote
Defang supplies the resolved provider and stack to the dev service. The
in-container Publish button therefore reuses the original deployment
context, including the matching provider env file.
The admin console's Publish panel promotes the live, agent-edited workspace
into a new production build — by having the dev container run
defang compose up on its own Compose project, overwriting both the dev
and app services. There is deliberately no GitOps pipeline: the deployed app
mutates its own deployment.
- Authorization is per publish. Clicking Publish starts an interactive
defang logininside the container; the console surfaces the login URL in a new tab and the admin must complete it for every deployment. No Defang token is stored anywhere. After login, the panel shows who you are signed in as — make sure it is the tenant that owns this stack — before the final "Deploy and overwrite" button. - Cloud credentials are ambient, not baked. The selected env file supplies
the
devservice's AWS task-role policy or GCP VM service-account role; the CLI reads those workload credentials directly. - History survives. The workspace's git history (one commit per agent run, one per publish, each referencing the database rows it addressed) rides along in the build context, so the next dev container continues the same lineage.
PUBLISH_PROVIDERandPUBLISH_STACKcome from Defang's resolved deployment context; the standalone local-development Compose file leaves publishing disabled.
Every successful agent run is committed in the agent worktree and fast-forwarded
into the live tree with trailers (Run-Id, Feedback-Id, Model) linking it to
the run and feedback rows in Postgres; a failed run is discarded in the worktree
and never reaches the live app. The
admin console's History panel lists the lineage, links agent commits to
their run logs, and offers an admin-only revert (a new commit authored as the
admin). Runs can be graded on demand ("Grade this run") with a second model
call.
- The Mastra Workspace filesystem is rooted at
todo-app/; it cannot edit its own agent server. - The agent listens only on
127.0.0.1insidedev. - Next.js server routes validate the Better Auth session and admin role before dispatching or reading agent runs.
- Every run ends with
tsc --noEmit. A failed check triggers one repair attempt and is reported as failed if the app still does not compile. - The production
appimage contains neither the coding agent nor application source files.
Title: Self-Improving Mastra Todo
Short Description: A Next.js todo app where an admin can turn stored user feedback into live code changes with a Mastra coding agent.
Tags: Mastra, Next.js, PostgreSQL, Better Auth, AI, Agents
Languages: TypeScript, JavaScript, Docker