|
| 1 | +# Change: Update Image Tag and Add SQLite Database Support |
| 2 | + |
| 3 | +## Why |
| 4 | + |
| 5 | +The Hagicode project has updated its versioning strategy and deployment defaults. The `latest` image tag is no longer used for the latest version, and new deployments now support SQLite as a lightweight database option for quick-start scenarios. The current generator defaults need to be updated to align with these changes. |
| 6 | + |
| 7 | +**Research Notes from pcode repository**: |
| 8 | +- SQLite is the default database provider in Hagicode with automatic path generation |
| 9 | +- Default SQLite connection string: `Data Source=./data/hagicode.db` (relative to app root) |
| 10 | +- Container data directory: `/app/data` (for volume mounts) |
| 11 | +- Image tags use semantic versioning (e.g., `0.1.0-beta.1`) instead of `latest` |
| 12 | +- Reference: `/home/newbe36524/repos/newbe36524/pcode` |
| 13 | + |
| 14 | +## What Changes |
| 15 | + |
| 16 | +- **BREAKING**: Update default image tag from `latest` to `0` (as placeholder for latest stable version) |
| 17 | +- **NEW**: Add `sqlite` as a new database type option |
| 18 | +- **MODIFIED**: Quick-start profile now defaults to SQLite instead of internal PostgreSQL |
| 19 | +- **MODIFIED**: Full-custom profile allows selection between SQLite, internal PostgreSQL, and external PostgreSQL |
| 20 | +- **NEW**: Add SQLite volume mount configuration for data persistence (`/app/data` mount point) |
| 21 | +- **MODIFIED**: Docker Compose generator to conditionally include/exclude PostgreSQL service based on database type |
| 22 | + |
| 23 | +**Implementation Details** (based on pcode repository analysis and design decisions): |
| 24 | +- **CRITICAL**: `Database__Provider` environment variable MUST be set based on database type |
| 25 | + - SQLite: `Database__Provider=sqlite` |
| 26 | + - PostgreSQL: `Database__Provider=postgresql` (or `PostgreSQL` - both work) |
| 27 | +- SQLite connection string format: `Data Source=/app/data/hagicode.db` (fixed container path) |
| 28 | +- PostgreSQL connection string format: `Host=postgres;Port=5432;Database=hagicode;Username=postgres;Password=postgres` |
| 29 | +- **`hagicode_data:/app/data` named volume is ALWAYS included** (regardless of database type) |
| 30 | + - Contains SQLite database file when using SQLite |
| 31 | + - Contains other application data (Orleans grain storage, logs, etc.) for all database types |
| 32 | +- Container path `/app/data` is **NOT user-configurable** (fixed by design) |
| 33 | +- Users **DO NOT** configure SQLite data directory path - it's always a named volume |
| 34 | +- SQLite requires no PostgreSQL service, no `depends_on` database dependency |
| 35 | +- Image tag `0` represents the latest stable version (aligning with pcode deployment practices) |
| 36 | + |
| 37 | +## UI Design Changes |
| 38 | + |
| 39 | +### Quick-Start Mode |
| 40 | +``` |
| 41 | +Docker Compose Generator - Quick Start |
| 42 | +======================================== |
| 43 | +
|
| 44 | +Required Fields: |
| 45 | +- [Work Directory Path: _________________ ] |
| 46 | +- [HTTP Port: 45000 ] |
| 47 | +- [API Token: __________________________ ] |
| 48 | +- [Image Registry: (x) Aliyun ACR ( ) Docker Hub ( ) Azure ACR] |
| 49 | +- [API Provider: (x) ZAI ( ) Anthropic ( ) Custom] |
| 50 | +
|
| 51 | +[Hidden: Database defaults to SQLite] |
| 52 | +[Hidden: All other fields use sensible defaults] |
| 53 | +
|
| 54 | +[Generate Configuration] [Copy] [Download] |
| 55 | +``` |
| 56 | + |
| 57 | +### Full-Custom Mode - Database Selection |
| 58 | +``` |
| 59 | +Database Configuration: |
| 60 | +====================== |
| 61 | +(x) SQLite - Lightweight, file-based database (recommended for quick start) |
| 62 | +( ) Internal PostgreSQL - Full PostgreSQL service running in container |
| 63 | +( ) External PostgreSQL - Connect to existing PostgreSQL instance |
| 64 | +
|
| 65 | +[If SQLite selected:] |
| 66 | +- Data stored in named volume (hagicode_data) mounted to /app/data (not user-configurable) |
| 67 | +
|
| 68 | +[If Internal PostgreSQL selected:] |
| 69 | +- Database Name: [hagicode_________ ] |
| 70 | +- Username: [postgres_________ ] |
| 71 | +- Password: [****************] |
| 72 | +- Volume Type: ( ) Named ( ) Bind Mount |
| 73 | +- Volume Path/Name: [postgres-data__________________________ ] |
| 74 | +
|
| 75 | +[If External PostgreSQL selected:] |
| 76 | +- Host: [____________________ ] |
| 77 | +- Port: [5432_______________ ] |
| 78 | +- Database: [hagicode_________ ] |
| 79 | +- Username: [postgres_________ ] |
| 80 | +- Password: [****************] |
| 81 | +``` |
| 82 | + |
| 83 | +### User Interaction Flow |
| 84 | +```mermaid |
| 85 | +sequenceDiagram |
| 86 | + participant User |
| 87 | + participant UI |
| 88 | + participant Generator |
| 89 | +
|
| 90 | + User->>UI: Selects Quick-Start mode |
| 91 | + UI->>UI: Set databaseType='sqlite' (hidden) |
| 92 | + User->>UI: Fills required fields |
| 93 | + User->>UI: Clicks Generate |
| 94 | + UI->>Generator: generateYAML(config) |
| 95 | + Generator->>Generator: buildAppService() with SQLite connection string |
| 96 | + Generator->>Generator: buildSqliteVolumes() |
| 97 | + Generator-->>UI: Returns YAML without PostgreSQL service |
| 98 | + UI-->>User: Displays docker-compose.yml |
| 99 | +
|
| 100 | + User->>UI: Switches to Full-Custom mode |
| 101 | + UI->>UI: Shows database selection |
| 102 | + User->>UI: Selects Internal PostgreSQL |
| 103 | + User->>UI: Clicks Generate |
| 104 | + UI->>Generator: generateYAML(config) |
| 105 | + Generator->>Generator: buildAppService() with PostgreSQL connection string |
| 106 | + Generator->>Generator: buildPostgresService() |
| 107 | + Generator-->>UI: Returns YAML with PostgreSQL service |
| 108 | + UI-->>User: Displays docker-compose.yml |
| 109 | +``` |
| 110 | + |
| 111 | +## Code Flow Changes |
| 112 | + |
| 113 | +### Database Configuration Flow |
| 114 | +```mermaid |
| 115 | +flowchart TD |
| 116 | + A[generateYAML] --> B{databaseType?} |
| 117 | + B -->|sqlite| C[buildAppService with SQLite] |
| 118 | + B -->|internal| D[buildAppService with PostgreSQL] |
| 119 | + B -->|external| E[buildAppService with PostgreSQL] |
| 120 | +
|
| 121 | + C --> F[buildSqliteVolumes] |
| 122 | + D --> G[buildPostgresService] |
| 123 | + E --> H[No PostgreSQL service] |
| 124 | +
|
| 125 | + F --> I[buildVolumesSection - check SQLite named volumes] |
| 126 | + G --> I |
| 127 | + H --> I |
| 128 | +
|
| 129 | + I --> J[Return YAML] |
| 130 | +``` |
| 131 | + |
| 132 | +### Component Relationship Changes |
| 133 | +```mermaid |
| 134 | +graph TD |
| 135 | + A[DockerComposeConfig] -->|NEW| B[DatabaseType: 'sqlite' option] |
| 136 | + A --> C[ConfigProfile: 'quick-start'] |
| 137 | + C -->|MODIFIED| D[Defaults to SQLite] |
| 138 | +
|
| 139 | + E[buildAppService] -->|NEW| F{Check SQLite} |
| 140 | + F -->|Yes| G[Set SQLite connection string] |
| 141 | + F -->|No| H[Set PostgreSQL connection string] |
| 142 | +
|
| 143 | + I[buildServicesSection] -->|NEW| J{Include PostgreSQL?} |
| 144 | + J -->|databaseType = 'internal'| K[buildPostgresService] |
| 145 | + J -->|databaseType = 'sqlite'| L[Skip PostgreSQL service] |
| 146 | +
|
| 147 | + M[NEW: buildSqliteVolumes] --> N[Configure named volume hagicode_data → /app/data] |
| 148 | +``` |
| 149 | + |
| 150 | +## Impact |
| 151 | + |
| 152 | +- Affected specs: `docker-compose-generator` |
| 153 | +- Affected code: |
| 154 | + - `src/lib/docker-compose/types.ts:6` - Add `'sqlite'` to `DatabaseType` |
| 155 | + - `src/lib/docker-compose/defaultConfig.ts:7` - Change `imageTag` from `'latest'` to `'0'` |
| 156 | + - `src/lib/docker-compose/defaultConfig.ts:12` - Change quick-start `databaseType` from `'internal'` to `'sqlite'` |
| 157 | + - `src/lib/docker-compose/generator.ts:57-152` - Modify `buildAppService()` to handle SQLite connection strings |
| 158 | + - `src/lib/docker-compose/generator.ts:207-223` - Modify `buildServicesSection()` to conditionally include PostgreSQL |
| 159 | + - `src/lib/docker-compose/generator.ts:230-241` - Modify `buildVolumesSection()` to handle SQLite named volume |
| 160 | + - New function: `buildSqliteVolumes()` in `src/lib/docker-compose/generator.ts` (generates named volume mount) |
| 161 | + |
| 162 | +**Design Decision: Application data volume** |
| 163 | +- Container path `/app/data` is **NOT user-configurable** |
| 164 | +- Named volume `hagicode_data` is **always created** for ALL database types |
| 165 | + - SQLite: stores database file + other app data |
| 166 | + - PostgreSQL: stores Orleans grain storage, logs, and other non-database data |
| 167 | +- Users **DO NOT** specify data directory path (simplified UX) |
| 168 | +- PostgreSQL database data uses separate volume (`postgres-data`) |
| 169 | + |
| 170 | +## Docker Compose Sample Comparison |
| 171 | + |
| 172 | +This section shows the expected YAML output changes for verification. |
| 173 | + |
| 174 | +### Before (current - PostgreSQL internal) |
| 175 | + |
| 176 | +```yaml |
| 177 | +services: |
| 178 | + hagicode: |
| 179 | + image: registry.cn-hangzhou.aliyuncs.com/hagicode/hagicode:latest |
| 180 | + container_name: hagicode-app |
| 181 | + environment: |
| 182 | + - ASPNETCORE_ENVIRONMENT=Production |
| 183 | + - ASPNETCORE_URLS=http://+:45000 |
| 184 | + - TZ=Asia/Shanghai |
| 185 | + - Database__Provider=PostgreSQL |
| 186 | + - ConnectionStrings__Default=Host=postgres;Port=5432;Database=hagicode;Username=postgres;Password=postgres |
| 187 | + # ... other env vars |
| 188 | + ports: |
| 189 | + - "45000:45000" |
| 190 | + volumes: |
| 191 | + - /home/user/repos:/app/workdir |
| 192 | + - hagicode_data:/app/data |
| 193 | + depends_on: |
| 194 | + postgres: |
| 195 | + condition: service_healthy |
| 196 | + networks: |
| 197 | + - pcode-network |
| 198 | + restart: unless-stopped |
| 199 | + |
| 200 | + postgres: |
| 201 | + image: bitnami/postgresql:latest |
| 202 | + container_name: hagicode-postgres |
| 203 | + environment: |
| 204 | + - POSTGRES_DATABASE=hagicode |
| 205 | + - POSTGRES_USER=postgres |
| 206 | + - POSTGRES_PASSWORD=postgres |
| 207 | + - POSTGRES_HOST_AUTH_METHOD=trust |
| 208 | + - TZ=Asia/Shanghai |
| 209 | + volumes: |
| 210 | + - postgres-data:/bitnami/postgresql |
| 211 | + healthcheck: |
| 212 | + test: ["CMD", "pg_isready", "-U", "postgres"] |
| 213 | + interval: 10s |
| 214 | + timeout: 3s |
| 215 | + retries: 3 |
| 216 | + networks: |
| 217 | + - pcode-network |
| 218 | + restart: unless-stopped |
| 219 | + |
| 220 | +volumes: |
| 221 | + hagicode_data: |
| 222 | + postgres-data: |
| 223 | + |
| 224 | +networks: |
| 225 | + pcode-network: |
| 226 | + driver: bridge |
| 227 | +``` |
| 228 | +
|
| 229 | +### After (new - SQLite default) |
| 230 | +
|
| 231 | +```yaml |
| 232 | +services: |
| 233 | + hagicode: |
| 234 | + image: registry.cn-hangzhou.aliyuncs.com/hagicode/hagicode:0 |
| 235 | + container_name: hagicode-app |
| 236 | + environment: |
| 237 | + - ASPNETCORE_ENVIRONMENT=Production |
| 238 | + - ASPNETCORE_URLS=http://+:45000 |
| 239 | + - TZ=Asia/Shanghai |
| 240 | + - Database__Provider=sqlite |
| 241 | + - ConnectionStrings__Default=Data Source=/app/data/hagicode.db |
| 242 | + # ... other env vars |
| 243 | + ports: |
| 244 | + - "45000:45000" |
| 245 | + volumes: |
| 246 | + - /home/user/repos:/app/workdir |
| 247 | + - hagicode_data:/app/data |
| 248 | + # NO depends_on for SQLite |
| 249 | + networks: |
| 250 | + - pcode-network |
| 251 | + restart: unless-stopped |
| 252 | + |
| 253 | +# NO postgres service when using SQLite |
| 254 | + |
| 255 | +volumes: |
| 256 | + hagicode_data: |
| 257 | + |
| 258 | +networks: |
| 259 | + pcode-network: |
| 260 | + driver: bridge |
| 261 | +``` |
| 262 | +
|
| 263 | +### Key Changes Summary |
| 264 | +
|
| 265 | +| Section | Before (PostgreSQL) | After (SQLite) | |
| 266 | +|---------|-------------------|---------------| |
| 267 | +| **Image tag** | `:latest` | `:0` | |
| 268 | +| **Database__Provider** | `Database__Provider=PostgreSQL` | `Database__Provider=sqlite` | |
| 269 | +| **Connection string** | `Host=postgres;Port=5432;...` | `Data Source=/app/data/hagicode.db` | |
| 270 | +| **hagicode_data volume** | Present (for Orleans/logs) | Present (for SQLite + Orleans/logs) | |
| 271 | +| **postgres-data volume** | Present (for PostgreSQL DB) | Removed | |
| 272 | +| **depends_on** | `postgres: condition: service_healthy` | (removed) | |
| 273 | +| **postgres service** | Included | Excluded | |
| 274 | +| **volumes section** | `hagicode_data:` + `postgres-data:` | `hagicode_data:` only | |
| 275 | + |
| 276 | +### Verification Checklist |
| 277 | + |
| 278 | +#### All Configurations (Common) |
| 279 | +- [ ] Image tag changed from `latest` to `0` |
| 280 | +- [ ] `hagicode_data:/app/data` volume is **always present** (for app data: Orleans, logs, etc.) |
| 281 | +- [ ] `volumes:` section **always defines** `hagicode_data:` |
| 282 | +- [ ] `networks:` section remains unchanged |
| 283 | + |
| 284 | +#### SQLite-Specific (Quick-Start / SQLite selected) |
| 285 | +- [ ] `Database__Provider=sqlite` environment variable set |
| 286 | +- [ ] Connection string uses SQLite format: `Data Source=/app/data/hagicode.db` |
| 287 | +- [ ] No `depends_on` for database |
| 288 | +- [ ] No `postgres` service in output |
| 289 | +- [ ] No `postgres-data` volume |
| 290 | + |
| 291 | +#### PostgreSQL-Specific (Internal PostgreSQL) |
| 292 | +- [ ] `Database__Provider=postgresql` (or `PostgreSQL`) environment variable set |
| 293 | +- [ ] Connection string uses PostgreSQL format: `Host=postgres;...` |
| 294 | +- [ ] `depends_on: postgres:` with healthcheck condition present |
| 295 | +- [ ] `postgres` service included with correct configuration |
| 296 | +- [ ] `volumes:` section includes `postgres-data:` (in addition to `hagicode_data:`) |
0 commit comments