Skip to content

Commit 641f348

Browse files
Merge pull request #126 from Digital-Alchemy-TS/server/dbLocation
Server/db location
2 parents 792e6aa + 8f359cf commit 641f348

12 files changed

Lines changed: 110 additions & 71 deletions

File tree

WARP.md

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,21 @@ Code Glue is a Home Assistant addon that allows users to write automations and c
1717

1818
### Runtime Structure in Container
1919
```
20-
/app/
21-
├── server/
22-
│ ├── dist/
23-
│ │ └── client/ # Static web files served here
24-
│ ├── app/
25-
│ │ └── environments/
26-
│ │ └── prebuilt/ # Production entry point
27-
│ ├── migrations/ # Database migration files
28-
│ │ ├── sqlite/
29-
│ │ ├── mysql/
30-
│ │ └── postgresql/
31-
│ └── drizzle.config.ts
20+
/work/ # Working directory
21+
├── dist/
22+
│ ├── server/ # Compiled server code
23+
│ └── client/ # Static web files
24+
├── apps/
25+
│ └── server/
26+
│ └── migrations/ # Database migration files
27+
│ ├── sqlite/
28+
│ ├── mysql/
29+
│ └── postgresql/
3230
├── node_modules/
3331
└── [other files]
32+
33+
/data/ # Persistent volume (Home Assistant provided)
34+
└── synapse_storage.db # SQLite database (persists across restarts)
3435
```
3536

3637
## Key Technologies
@@ -78,23 +79,23 @@ The server has multiple entry points in `dist/server/app/environments/`:
7879
### Prebuilt Environment
7980
- Entry: `dist/server/app/environments/prebuilt/main.mjs`
8081
- Sets `SERVE_STATIC=true` and `ATTACH_STANDARD_MIDDLEWARE=true`
81-
- Expects client at `process.cwd() + '/server/dist/client'``/app/server/dist/client/`
82+
- Expects client at `process.cwd() + '/dist/client'``/work/dist/client/`
8283
- Runs on port 3789 (configurable via PORT env var)
8384

8485
## Static File Serving
8586

8687
The server's `StaticFileService` (`apps/server/src/http/services/static.service.mts`):
8788
- Looks for client at `path.resolve(process.cwd(), "dist/client")`
88-
- With workdir `/app`, this resolves to `/app/dist/client`
89-
- **Current setup**: Client copied to `/app/server/dist/client/` in Dockerfile
89+
- With workdir `/work`, this resolves to `/work/dist/client`
90+
- **Current setup**: Client copied to `/work/dist/client/` in Dockerfile
9091
- Serves SPA with catch-all routing (all non-API routes → `index.html`)
9192

9293
## Container Startup Flow
9394

9495
1. **Entrypoint script** (`scripts/docker-entrypoint.sh`):
95-
- Runs database migrations: `cd /app/server && npx drizzle-kit migrate`
96-
- Sets `DATABASE_URL=file:/app/synapse_storage.db`
97-
- Starts server: `tsx /app/server/app/environments/prebuilt/main.mjs`
96+
- Runs database migrations: `cd /work/apps/server && npx drizzle-kit migrate`
97+
- Sets `DATABASE_URL=file:/data/synapse_storage.db`
98+
- Starts server: `node dist/server/app/environments/prebuilt/main.mjs`
9899

99100
2. **Server bootstrap**:
100101
- Initializes Digital Alchemy services
@@ -123,7 +124,7 @@ The server's `StaticFileService` (`apps/server/src/http/services/static.service.
123124

124125
### 404 Errors on Web UI
125126
- **Cause**: Static files not at expected path
126-
- **Fix**: Ensure client copied to `/app/server/dist/client/` in Dockerfile to match `StaticFileService` expectations
127+
- **Fix**: Ensure client copied to `/work/dist/client/` in Dockerfile to match `StaticFileService` expectations
127128

128129
### "Can't find meta/_journal.json" Error
129130
- **Cause**: `DatabaseInternalsService` tries to run migrations but looks in wrong location
@@ -178,11 +179,11 @@ The repo includes `.devcontainer/devcontainer.json` using `ghcr.io/home-assistan
178179

179180
| Description | Path in Container | Source in Build |
180181
|-------------|------------------|-----------------|
181-
| Server code | `/app/server/` | `dist/server/` |
182-
| Client static files | `/app/server/dist/client/` | `apps/client/dist/` |
183-
| Migrations | `/app/server/migrations/` | `apps/server/migrations/` |
184-
| Database | `/app/synapse_storage.db` | Created at runtime |
185-
| Node modules | `/app/node_modules/` | Copied from build stage |
182+
| Server code | `/work/dist/server/` | `dist/server/` |
183+
| Client static files | `/work/dist/client/` | `apps/client/dist/` |
184+
| Migrations | `/work/apps/server/migrations/` | `apps/server/migrations/` |
185+
| Database | `/data/synapse_storage.db` | Created at runtime (persistent volume) |
186+
| Node modules | `/work/node_modules/` | Copied from build stage |
186187
| Entrypoint | `/docker-entrypoint.sh` | `scripts/docker-entrypoint.sh` |
187188

188189
## Testing Checklist

apps/client/.vscode/settings.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,15 @@
2121
"files.exclude": {
2222
"dist/": true,
2323
".tamagui": true
24+
},
25+
"explorer.fileNesting.enabled": true,
26+
"explorer.fileNesting.patterns": {
27+
"package.json": "package-lock.json, yarn.lock, .yarnrc.yml, cspell.config.yaml, biome.json, LICENSE, .gitignore, README.md",
28+
".env.example": ".env",
29+
"tsconfig.json": "vite-env.d.ts, vitest.shims.d.ts",
30+
"index.tsx": "stories.tsx",
31+
"*.js": "${capture}.js.map, ${capture}.d.ts, ${capture}.d.ts.map",
32+
"*.ts": "$(capture).test.ts, $(capture).test.tsx, $(capture).test.node.ts, $(capture).test.node.tsx, $(capture).test.native.ts, $(capture).test.native.tsx, $(capture).test.ios.ts, $(capture).test.ios.tsx, $(capture).test.web.ts, $(capture).test.web.tsx, $(capture).test.android.ts, $(capture).test.android.tsx, ${capture}.native.tsx, ${capture}.ios.tsx, ${capture}.android.tsx, ${capture}.web.tsx, ${capture}.native.ts, ${capture}.ios.ts, ${capture}.android.ts, ${capture}.web.ts, ${capture}.native.js, ${capture}.ios.js, ${capture}.android.js, ${capture}.web.js, ${capture}.native.jsx, ${capture}.ios.jsx, ${capture}.android.jsx, ${capture}.web.jsx, ${capture}.stories.tsx, ${capture}.story.tsx, ${capture}.stories.ts, ${capture}.stories.jsx, ${capture}.stories.js",
33+
"*.tsx": "$(capture).test.ts, $(capture).test.tsx, $(capture).test.node.ts, $(capture).test.node.tsx, $(capture).test.native.ts, $(capture).test.native.tsx, $(capture).test.ios.ts, $(capture).test.ios.tsx, $(capture).test.web.ts, $(capture).test.web.tsx, $(capture).test.android.ts, $(capture).test.android.tsx, ${capture}.native.tsx, ${capture}.ios.tsx, ${capture}.android.tsx, ${capture}.web.tsx, ${capture}.native.ts, ${capture}.ios.ts, ${capture}.android.ts, ${capture}.web.ts, ${capture}.native.js, ${capture}.ios.js, ${capture}.android.js, ${capture}.web.js, ${capture}.native.jsx, ${capture}.ios.jsx, ${capture}.android.jsx, ${capture}.web.jsx, ${capture}.stories.tsx, ${capture}.stories.ts, ${capture}.stories.jsx, ${capture}.stories.js"
2434
}
2535
}

apps/client/app.config.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type GenericParserBuilder, parseAsString } from "nuqs"
1+
import { type GenericParserBuilder, parseAsBoolean, parseAsString } from "nuqs"
22

33
import { codeGlueLight } from "./src/design/editorThemes"
44

@@ -40,6 +40,9 @@ export const appConfig = {
4040
defaultFontSize: 14,
4141
font: "Monaspace Krypton",
4242
},
43+
queries: {
44+
settings: parseAsBoolean.withDefault(false),
45+
},
4346
routes: {
4447
home: { title: "Logs" }, // home is a special route name that will show without params in the URL
4548
automations: {
@@ -57,6 +60,7 @@ export const sectionIds = Object.keys(appConfig.routes) as Array<
5760
keyof typeof appConfig.routes
5861
>
5962

63+
export type QueryIds = keyof typeof appConfig.queries
6064
export type SectionIds = keyof typeof appConfig.routes
6165
export type SectionTitles =
6266
(typeof appConfig.routes)[keyof typeof appConfig.routes]["title"]

apps/client/src/hooks/useQuery.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { useQueryState } from "nuqs"
2+
3+
import { appConfig, type QueryIds } from "@/config"
4+
5+
export function useQuery(queryId: QueryIds) {
6+
return useQueryState(queryId, appConfig.queries[queryId])
7+
}
Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,59 @@
11
import { useSnapshot } from "valtio"
22

33
import { Button, Column, Icon, List, ListItem } from "@code-glue/paradigm"
4+
import { useQuery } from "@/hooks/useQuery"
45
import { useRouter } from "@/hooks/useRouter"
56
import { store } from "@/store"
67
import { CreateAutomation } from "../../components/CreateAutomation"
78
import { Header } from "../../components/Header"
9+
import { Settings } from "./Settings"
810
export const Nav = () => {
911
const { automations } = useSnapshot(store)
10-
1112
const [{ route, automationId }, navigateTo] = useRouter()
13+
const [isSettings, setIsSettings] = useQuery("settings")
1214

1315
return (
1416
<Column grow color={"$cardStock"}>
1517
<Header>
1618
<img src="./headerLogo.png" alt="CodeGlue" height={42} />
17-
<Button icon={Icon.Settings} isRaised />
19+
<Button
20+
icon={isSettings ? Icon.X : Icon.Settings}
21+
isRaised
22+
onPress={() => {
23+
setIsSettings(!isSettings)
24+
}}
25+
/>
1826
</Header>
19-
<List.Group>
20-
<List.Simple>
21-
<ListItem
22-
label="Logs"
23-
isSelected={!route}
24-
onPress={() => navigateTo("home")}
25-
/>
26-
</List.Simple>
27-
<List.Simple header="Automations">
28-
<CreateAutomation />
29-
{Array.from(automations, ([, automation]) => {
30-
return (
31-
<ListItem
32-
label={automation.title}
33-
key={automation.id}
34-
isSelected={
35-
route === "automations" && automation.id === automationId
36-
}
37-
onPress={() => {
38-
navigateTo("automations", { automationId: automation.id })
39-
}}
40-
/>
41-
)
42-
})}
43-
</List.Simple>
44-
</List.Group>
27+
{isSettings ? (
28+
<Settings />
29+
) : (
30+
<List.Group>
31+
<List.Simple>
32+
<ListItem
33+
label="Logs"
34+
isSelected={!route}
35+
onPress={() => navigateTo("home")}
36+
/>
37+
</List.Simple>
38+
<List.Simple header="Automations">
39+
<CreateAutomation />
40+
{Array.from(automations, ([, automation]) => {
41+
return (
42+
<ListItem
43+
label={automation.title}
44+
key={automation.id}
45+
isSelected={
46+
route === "automations" && automation.id === automationId
47+
}
48+
onPress={() => {
49+
navigateTo("automations", { automationId: automation.id })
50+
}}
51+
/>
52+
)
53+
})}
54+
</List.Simple>
55+
</List.Group>
56+
)}
4557
</Column>
4658
)
4759
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { Text } from "@code-glue/paradigm"
2+
3+
export const Settings = () => {
4+
return <Text>Settings</Text>
5+
}

apps/client/src/pages/Settings.tsx

Whitespace-only changes.

apps/server/drizzle.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const configs = {
1717
dialect: "sqlite" as const,
1818
out: "./migrations/sqlite",
1919
dbCredentials: {
20-
url: process.env.DATABASE_URL || "file:./synapse_storage.db",
20+
url: process.env.DATABASE_URL || "file:/data/synapse_storage.db",
2121
},
2222
},
2323
postgresql: {

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
"typecheck": "yarn workspaces foreach -Avi run typecheck",
1818
"clean": "sh ./scripts/clean.sh"
1919
},
20-
"packageManager": "yarn@4.10.3",
20+
"packageManager": "yarn@4.12.0",
2121
"volta": {
2222
"node": "22.12.0",
23-
"yarn": "4.10.3"
23+
"yarn": "4.12.0"
2424
},
2525
"resolutions": {
2626
"jsonpath-plus": "10.0.7",

0 commit comments

Comments
 (0)