~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/hatk

AT Protocol app framework

1
0
main
113 lines · 4.5 KB Raw History
# Template System Design

## Context

The `hatk new` command currently scaffolds a bare project with empty directories and core framework lexicons. Users building AT Protocol apps need a way to start from a working example rather than an empty shell. The Statusphere app (from the ATConf workshop) is the first template — a complete working app with custom lexicons, feeds, XRPC handlers, seeds, a Svelte frontend, and tests.

## Design

### CLI Interface

```
hatk new my-app --template statusphere
```

- `--template <name>` selects a bundled template
- Without `--template`, behaves exactly as today (bare scaffold)
- `--svelte` flag is still respected; templates can also declare `"svelte": true` in their manifest

### How It Works

1. **Scaffold first** — run the normal scaffold logic (config.yaml, package.json, docker-compose.yml, Dockerfile, core `dev.hatk.*` lexicons, tsconfig, linting config, .gitignore)
2. **Read manifest** — load `template.json` from the template directory
3. **Apply Svelte** — if manifest declares `"svelte": true`, generate SvelteKit files (same as `--svelte`)
4. **Merge config** — deep-merge template's `config` object into the generated config.yaml
5. **Merge dependencies** — add template's `dependencies` and `devDependencies` to package.json
6. **Copy files** — recursively copy all template files (except template.json) into the project, overwriting scaffold defaults where they overlap
7. **Finalize** — run `npm install`, `hatk generate types`, and `svelte-kit sync` if Svelte

### Template Location

Templates are bundled inside the hatk package at `packages/appview/templates/<name>/`. Discovered by listing directories in `templates/`.

### Template Structure

```
packages/appview/templates/statusphere/
├── template.json
├── lexicons/
│   └── xyz/statusphere/
│       ├── defs.json
│       ├── status.json
│       └── getProfile.json
├── feeds/
│   └── recent.ts
├── xrpc/
│   └── xyz/statusphere/
│       └── getProfile.ts
├── seeds/
│   └── seed.ts
├── test/
│   ├── feeds/
│   │   └── recent.test.ts
│   └── fixtures/
│       ├── _repos.yaml
│       ├── app.bsky.actor.profile.yaml
│       └── xyz.statusphere.status.yaml
└── src/
    ├── routes/
    │   ├── +page.svelte
    │   ├── +layout.svelte
    │   └── oauth/callback/+page.svelte
    ├── lib/
    │   ├── api.ts
    │   ├── auth.ts
    │   └── query.ts
    ├── app.html
    ├── app.css
    └── error.html
```

### template.json Manifest

```json
{
  "description": "Statusphere example app",
  "svelte": true,
  "dependencies": {
    "@tanstack/svelte-query": "^5"
  },
  "config": {
    "oauth": {
      "scope": "atproto repo:xyz.statusphere.status?action=create&action=delete"
    }
  }
}
```

| Field | Type | Description |
|-------|------|-------------|
| `description` | string | Shown in help text / template listing |
| `svelte` | boolean | Auto-enable SvelteKit scaffold |
| `dependencies` | object | Merged into package.json dependencies |
| `devDependencies` | object | Merged into package.json devDependencies |
| `config` | object | Deep-merged into generated config.yaml |

### Files to Modify

- **`packages/appview/src/cli.ts`** — add `--template` flag parsing, template discovery, manifest loading, config merging, dependency merging, file copying
- **`packages/appview/templates/statusphere/`** — new directory with template files copied from exercise 10 (with NSIDs kept as `xyz.statusphere.*`, imports updated to use `hatk/` package names and `hatk.generated.ts`)

### Key Decisions

- Templates are plain file copies — no string interpolation or parameterization
- `xyz.statusphere.*` NSIDs are kept as-is (they're the app's domain, not the framework's)
- Template's config is deep-merged, not replaced — base config (relay, plc, port, database) stays intact
- If a template includes `src/`, it implies Svelte — the manifest's `"svelte": true` ensures the scaffold generates SvelteKit config files before the template's frontend files are copied on top

## Verification

1. Run `hatk new test-app` — should produce bare scaffold as before (no regression)
2. Run `hatk new test-app --template statusphere` — should produce a working Statusphere app
3. `cd test-app && npm install && hatk dev` — app should start and be functional
4. Run `hatk test` — tests should pass