first commit

This commit is contained in:
npc0-hue
2026-07-11 14:56:10 +08:00
commit 7e05d0a4e7
660 changed files with 78119 additions and 0 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-07-07
@@ -0,0 +1,51 @@
## Context
The platform already supports file and MySQL-backed metadata stores behind `repo.Store`. MySQL initialization is selected by `PLATFORM_STORAGE_BACKEND=mysql` and uses `PLATFORM_MYSQL_DSN`, but `platform/cmd/platform` calls `config.Load()` directly and `config.Load()` only reads process environment variables. A developer who edits `platform/.env` and starts the binary without sourcing that file still gets the default file-backed store.
The platform web shell currently embeds profile editing, theme palette selection, background presets, upload background, and logout inside the sidebar account popover. Those controls already call the current-user profile and theme APIs, but the interaction is cramped and visually hard to use.
## Goals / Non-Goals
**Goals:**
- Load repository-local `.env` values into platform configuration before storage initialization.
- Preserve process environment precedence over `.env` values so deployment systems can override local files.
- Keep profile and theme persistence backed by existing user APIs and the configured metadata repository.
- Replace the account popover editor with a dedicated personal settings page that is available to all authenticated users.
- Preserve the current magical crystal-moonlight shell style and shared surface classes.
**Non-Goals:**
- Add a normalized relational user schema or migrations beyond the existing MySQL metadata snapshot table.
- Add external account providers, billing, cloud host provisioning, or plugin marketplace workflows.
- Expose raw credentials, host paths, or direct run/plugin internals to the web UI.
## Decisions
1. **Load `.env` inside `platform/config`**
- `config.Load()` will call a small local dotenv loader before reading values.
- The loader will check common local paths such as `.env` and `platform/.env` relative to the current working directory.
- Existing process environment values win over file values.
- Alternative considered: requiring users to `source .env`. Rejected because the observed failure is that local `.env` exists but platform startup does not consume it.
2. **Keep MySQL persistence through the existing snapshot repository**
- The fix only makes backend selection reliable; it does not introduce normalized SQL tables for users.
- Profile and theme updates already flow through `UpdateUser`, which persists through `repo.Store`; this remains the single write path.
- Alternative considered: adding user-specific SQL tables now. Rejected because it is broader than the current bug and would duplicate the existing store abstraction.
3. **Move personal settings to a route instead of a popover**
- Add a `profileSettings` page id, route, registry entry, and page component.
- The sidebar account control becomes a navigation entry point to that page, with logout remaining available from the settings page.
- Theme controls move into the page but continue to use `theme/tokens.ts` helpers and the session store API methods.
- Alternative considered: converting the popover into a larger drawer. Rejected because the user specifically wants a normal personal configuration interface, and a page is more ergonomic for forms and preview grids.
## Risks / Trade-offs
- [Risk] `.env` parsing can accidentally override production environment values. → Mitigation: only set variables that are not already present in `os.Environ`.
- [Risk] Multiple working directories make `.env` discovery ambiguous. → Mitigation: try root `.env` and `platform/.env` from the process working directory, and use deterministic later-file fallback only for missing keys.
- [Risk] Uploaded background data URLs can be large. → Mitigation: preserve the existing client-side behavior and persistence API contract rather than expanding backend payload rules in this change.
- [Risk] Removing the popover editor changes a familiar access point. → Mitigation: keep the sidebar account button visible and route it directly to the new personal settings page.
## Migration Plan
1. Add dotenv loading tests that prove `platform/.env` selects MySQL settings and explicit process env overrides file values.
2. Add the personal settings route/page and update existing shell/session wiring to keep API-backed persistence.
3. Validate OpenSpec, backend config tests, frontend tests/typecheck/build, structure checks, and a browser walkthrough for the personal settings page.
@@ -0,0 +1,30 @@
## Why
Local operators can configure `platform/.env`, but the platform process currently reads only inherited environment variables. This makes MySQL metadata storage look uninitialized even when the `.env` file contains the correct `PLATFORM_STORAGE_BACKEND=mysql` and `PLATFORM_MYSQL_DSN` settings.
The current personal configuration experience is embedded in the sidebar account popover, which is cramped for profile, theme, and background preferences. Operators need a normal first-party personal settings page that saves profile and theme changes through platform APIs so values are durable in the configured metadata store.
## What Changes
- Load platform environment variables from local `.env` files before building platform configuration, while preserving explicit process environment overrides.
- Keep MySQL metadata initialization database-backed and make configured storage selection testable so operators can verify the remote metadata store is actually used.
- Replace the sidebar profile popover with a dedicated personal settings page for profile, theme palette, background preset, uploaded background, and logout actions.
- Add the personal settings route to the shell for authenticated users and keep account edits wired to `/api/v1/users/current/profile` and `/api/v1/users/current/theme`.
- Preserve the magical-girl crystal-moonlight visual system by reusing shared shell/page surfaces and theme tokens rather than adding a one-off UI style.
## Capabilities
### New Capabilities
- `platform-env-bootstrap`: Platform startup loads local environment configuration and initializes the configured metadata backend predictably.
- `personal-settings-workspace`: Authenticated users manage their own profile and console theme preferences from a full settings page backed by platform APIs.
### Modified Capabilities
- None.
## Impact
- Affects `platform/config` and platform startup tests for `.env` loading and storage backend selection.
- Affects `platform_web` route definitions, page registry, shell account controls, session usage, API-bound personal settings UI, tests, and shared styling.
- Does not add billing, cloud host sales, external marketplace behavior, raw AI key exposure, or plugin direct access to platform/run internals.
@@ -0,0 +1,34 @@
## ADDED Requirements
### Requirement: Authenticated users have a personal settings page
The platform web application SHALL provide a normal page-level personal settings workspace for every authenticated user.
#### Scenario: User opens personal settings
- **WHEN** an authenticated user activates the account settings entry point
- **THEN** the application MUST navigate to a full personal settings page instead of opening a cramped profile popover
#### Scenario: User sees current account data
- **WHEN** the personal settings page renders
- **THEN** it MUST show the current user's display name, email, role labels, status, profile fields, theme palette, background preset, and custom background state
### Requirement: Personal profile saves through platform APIs
The personal settings page SHALL save editable profile fields through platform-mediated current-user APIs.
#### Scenario: User saves profile
- **WHEN** a user submits display name, avatar URL, phone, QQ, or contact note changes
- **THEN** the page MUST call the current-user profile API and render the updated current user from the response
#### Scenario: Profile API is unavailable
- **WHEN** the current-user profile API cannot be reached in local development fallback mode
- **THEN** the page MUST mark the resulting profile state as local fallback rather than pretending database persistence succeeded
### Requirement: Theme preferences save through platform APIs
The personal settings page SHALL save theme palette, background preset, and custom background preferences through platform-mediated current-user APIs where available.
#### Scenario: User changes theme preference
- **WHEN** a user selects a palette, selects a background preset, uploads a background, or removes a background
- **THEN** the page MUST update the visible theme and persist the preference through the current-user theme API
#### Scenario: Theme API is unavailable
- **WHEN** the current-user theme API cannot be reached in local development fallback mode
- **THEN** the page MUST preserve local theme preference behavior and clearly show that the preference is local
@@ -0,0 +1,23 @@
## ADDED Requirements
### Requirement: Platform startup loads local environment files
The platform SHALL load local `.env` configuration before constructing runtime configuration for storage initialization.
#### Scenario: Platform env file selects MySQL storage
- **WHEN** `platform/.env` contains `PLATFORM_STORAGE_BACKEND=mysql` and `PLATFORM_MYSQL_DSN`
- **THEN** platform configuration MUST use the MySQL storage backend and DSN from the env file
#### Scenario: Process environment overrides env file
- **WHEN** a process environment variable and a local `.env` file both define the same platform setting
- **THEN** platform configuration MUST use the process environment value
### Requirement: Metadata backend selection remains database-backed
The platform SHALL initialize the configured metadata repository through the existing store boundary rather than falling back to hardcoded local sample data.
#### Scenario: MySQL storage is configured
- **WHEN** `PLATFORM_STORAGE_BACKEND=mysql` and a non-empty `PLATFORM_MYSQL_DSN` are loaded
- **THEN** platform startup MUST initialize the MySQL metadata store
#### Scenario: MySQL storage is missing DSN
- **WHEN** `PLATFORM_STORAGE_BACKEND=mysql` is loaded without `PLATFORM_MYSQL_DSN`
- **THEN** platform startup MUST fail with a direct configuration error instead of silently using file or memory storage
@@ -0,0 +1,31 @@
## 1. Platform Env Bootstrap
- [x] 1.1 Add a small dotenv loader in `platform/config` that reads local `.env` files without overriding explicit process environment values.
- [x] 1.2 Add config tests for `platform/.env` MySQL settings, process env precedence, and missing DSN behavior through storage initialization.
## 2. Personal Settings Workspace
- [x] 2.1 Add a first-party personal settings route, page id, registry entry, and navigation entry point for authenticated users.
- [x] 2.2 Move profile, theme palette, background preset, uploaded background, and logout controls from the sidebar popover into the new page.
- [x] 2.3 Keep profile and theme saves wired to current-user APIs and show API vs local fallback persistence state.
- [x] 2.4 Add/update frontend tests for routing, shell account navigation, and profile/theme API calls.
## 3. Verification
- [x] 3.1 Run `cd platform && go test ./config ./api ./service ./repo -count=1`.
- [x] 3.2 Run `cd platform_web && npm run typecheck && npm test && npm run build`.
- [x] 3.3 Run `scripts/check-structure.sh`.
- [x] 3.4 Run `openspec validate fix-env-profile-settings --strict`.
- [x] 3.5 Perform a browser walkthrough for the personal settings page and record the result.
## Verification Evidence
- 2026-07-07: `cd platform && go test ./config ./api ./service ./repo -count=1` passed.
- 2026-07-07: `cd platform_web && npm run typecheck` passed.
- 2026-07-07: `cd platform_web && npm test` passed with 11 files / 47 tests.
- 2026-07-07: `cd platform_web && npm run build` passed and Vite produced `dist/` assets.
- 2026-07-07: `scripts/check-structure.sh` passed.
- 2026-07-07: `openspec validate fix-env-profile-settings --strict` reported the change is valid; PostHog telemetry flush failed due restricted DNS and did not affect validation.
- 2026-07-07: Started `cd platform_web && npm run dev -- --port 5173`; Vite served the app at `http://127.0.0.1:5174/` because 5173 was occupied. Browser walkthrough could not be completed in this tool session because no in-app browser/Chrome control tool or local Playwright/Puppeteer dependency was exposed.
- 2026-07-08: Rechecked task `3.5` before generating the next architecture-stream OpenSpec. The browser walkthrough remains explicitly blocked in this session: an in-app browser connection opened the auth page at `http://127.0.0.1:5177/`, but DOM snapshot capture failed with `TypeError: o.incrementalAriaSnapshot is not a function`; the fallback-enabled dev server then failed to bind requested localhost ports with `listen EPERM` for `127.0.0.1:5180`, `127.0.0.1:5173`, and `127.0.0.1:5177`. The walkthrough is not accepted; it must be rerun manually or in a working browser/dev-server session before closing this change.
- 2026-07-08: Browser walkthrough accepted after starting the platform API with file storage at `127.0.0.1:18080` and using the existing Vite dev server at `127.0.0.1:5173`. Logged in with the seeded API-backed platform administrator `operator.local@example.test`, landed on `#/home`, opened `#/profile`, verified `个人设置` showed `API 已连接`, `Operator`, `operator.local@example.test`, `active`, and platform-admin navigation. Edited the contact note to `api walkthrough verified 2026-07-08`, clicked `保存资料`, observed `个人资料已保存到数据库`, reloaded `#/profile`, and confirmed the note value persisted through the API-backed session.