feat(sprint18): editor autosave/reset, admin auth, QR reuse, Ed25519 prep
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
- Project editor: persist draft to localStorage, restore on reload, last-saved/draft-restored status indicators, section/whole-draft reset with confirmation. - Extract shared QR/polling/expiry engine from TelegramLoginComponent (shared/qr-login) and reuse it for a new admin login flow. - Admin authentication kept fully separate from customer session: own cookie/localStorage keys, signals, guard, and header interceptor (core/admin-auth). - ?login=true / ?adminLogin=true open the respective login dialog for manual testing. - Ed25519 challenge/verify interfaces (fail-closed no-op binding) ready for backend delivery. - Document autosave/reset/admin-auth/QR-reuse/Ed25519 model and the remaining full-field-coverage gap in docs/Project-Editor.md.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BootstrapConfig } from '../../../shared/models/config';
|
||||
|
||||
const DRAFT_STORAGE_KEY = 'projectEditor.draftBootstrap.v1';
|
||||
const DRAFT_SAVED_AT_KEY = 'projectEditor.draftSavedAt.v1';
|
||||
|
||||
interface StoredDraft {
|
||||
tenantId: string;
|
||||
bootstrap: BootstrapConfig;
|
||||
savedAt: number;
|
||||
}
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ProjectEditorDraftStorageService {
|
||||
save(bootstrap: BootstrapConfig): number {
|
||||
const savedAt = Date.now();
|
||||
const payload: StoredDraft = { tenantId: bootstrap.tenant.id, bootstrap, savedAt };
|
||||
try {
|
||||
localStorage.setItem(DRAFT_STORAGE_KEY, JSON.stringify(payload));
|
||||
localStorage.setItem(DRAFT_SAVED_AT_KEY, String(savedAt));
|
||||
} catch {
|
||||
// storage unavailable (private mode / quota) - draft simply won't persist
|
||||
}
|
||||
return savedAt;
|
||||
}
|
||||
|
||||
load(tenantId: string): { bootstrap: BootstrapConfig; savedAt: number } | null {
|
||||
try {
|
||||
const raw = localStorage.getItem(DRAFT_STORAGE_KEY);
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
const parsed = JSON.parse(raw) as StoredDraft;
|
||||
if (parsed.tenantId !== tenantId) {
|
||||
return null;
|
||||
}
|
||||
return { bootstrap: parsed.bootstrap, savedAt: parsed.savedAt };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
try {
|
||||
localStorage.removeItem(DRAFT_STORAGE_KEY);
|
||||
localStorage.removeItem(DRAFT_SAVED_AT_KEY);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user