Initial commit: ArchiTools modular dashboard platform

Complete Next.js 16 application with 13 fully implemented modules:
Email Signature, Word XML Generator, Registratura, Dashboard,
Tag Manager, IT Inventory, Address Book, Password Vault,
Mini Utilities, Prompt Generator, Digital Signatures,
Word Templates, and AI Chat.

Includes core platform systems (module registry, feature flags,
storage abstraction, i18n, theming, auth stub, tagging),
16 technical documentation files, Docker deployment config,
and legacy HTML tool reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Marius Tarau
2026-02-17 12:50:25 +02:00
commit 4c46e8bcdd
189 changed files with 33780 additions and 0 deletions
@@ -0,0 +1,80 @@
import type { StorageService } from '../types';
function nsKey(namespace: string, key: string): string {
return `architools:${namespace}:${key}`;
}
function nsPrefix(namespace: string): string {
return `architools:${namespace}:`;
}
export class LocalStorageAdapter implements StorageService {
async get<T>(namespace: string, key: string): Promise<T | null> {
if (typeof window === 'undefined') return null;
try {
const raw = window.localStorage.getItem(nsKey(namespace, key));
if (raw === null) return null;
return JSON.parse(raw) as T;
} catch {
return null;
}
}
async set<T>(namespace: string, key: string, value: T): Promise<void> {
if (typeof window === 'undefined') return;
window.localStorage.setItem(nsKey(namespace, key), JSON.stringify(value));
}
async delete(namespace: string, key: string): Promise<void> {
if (typeof window === 'undefined') return;
window.localStorage.removeItem(nsKey(namespace, key));
}
async list(namespace: string): Promise<string[]> {
if (typeof window === 'undefined') return [];
const prefix = nsPrefix(namespace);
const keys: string[] = [];
for (let i = 0; i < window.localStorage.length; i++) {
const k = window.localStorage.key(i);
if (k && k.startsWith(prefix)) {
keys.push(k.slice(prefix.length));
}
}
return keys;
}
async query<T>(namespace: string, predicate: (item: T) => boolean): Promise<T[]> {
const keys = await this.list(namespace);
const results: T[] = [];
for (const key of keys) {
const item = await this.get<T>(namespace, key);
if (item !== null && predicate(item)) {
results.push(item);
}
}
return results;
}
async clear(namespace: string): Promise<void> {
if (typeof window === 'undefined') return;
const keys = await this.list(namespace);
for (const key of keys) {
window.localStorage.removeItem(nsKey(namespace, key));
}
}
async export(namespace: string): Promise<Record<string, unknown>> {
const keys = await this.list(namespace);
const data: Record<string, unknown> = {};
for (const key of keys) {
data[key] = await this.get(namespace, key);
}
return data;
}
async import(namespace: string, data: Record<string, unknown>): Promise<void> {
for (const [key, value] of Object.entries(data)) {
await this.set(namespace, key, value);
}
}
}
+4
View File
@@ -0,0 +1,4 @@
export type { StorageService } from './types';
export { StorageProvider, useStorageService } from './storage-provider';
export { useStorage } from './use-storage';
export type { NamespacedStorage } from './use-storage';
+33
View File
@@ -0,0 +1,33 @@
'use client';
import { createContext, useContext, useMemo } from 'react';
import type { StorageService } from './types';
import { LocalStorageAdapter } from './adapters/local-storage';
const StorageContext = createContext<StorageService | null>(null);
function createAdapter(): StorageService {
// Future: select adapter based on environment variable
// const adapterType = process.env.NEXT_PUBLIC_STORAGE_ADAPTER;
return new LocalStorageAdapter();
}
interface StorageProviderProps {
children: React.ReactNode;
}
export function StorageProvider({ children }: StorageProviderProps) {
const service = useMemo(() => createAdapter(), []);
return (
<StorageContext.Provider value={service}>
{children}
</StorageContext.Provider>
);
}
export function useStorageService(): StorageService {
const ctx = useContext(StorageContext);
if (!ctx) throw new Error('useStorageService must be used within StorageProvider');
return ctx;
}
+10
View File
@@ -0,0 +1,10 @@
export interface StorageService {
get<T>(namespace: string, key: string): Promise<T | null>;
set<T>(namespace: string, key: string, value: T): Promise<void>;
delete(namespace: string, key: string): Promise<void>;
list(namespace: string): Promise<string[]>;
query<T>(namespace: string, predicate: (item: T) => boolean): Promise<T[]>;
clear(namespace: string): Promise<void>;
export(namespace: string): Promise<Record<string, unknown>>;
import(namespace: string, data: Record<string, unknown>): Promise<void>;
}
+55
View File
@@ -0,0 +1,55 @@
'use client';
import { useCallback, useMemo } from 'react';
import { useStorageService } from './storage-provider';
export interface NamespacedStorage {
get: <T>(key: string) => Promise<T | null>;
set: <T>(key: string, value: T) => Promise<void>;
delete: (key: string) => Promise<void>;
list: () => Promise<string[]>;
query: <T>(predicate: (item: T) => boolean) => Promise<T[]>;
clear: () => Promise<void>;
exportAll: () => Promise<Record<string, unknown>>;
importAll: (data: Record<string, unknown>) => Promise<void>;
}
export function useStorage(namespace: string): NamespacedStorage {
const service = useStorageService();
const get = useCallback(
<T,>(key: string) => service.get<T>(namespace, key),
[service, namespace]
);
const set = useCallback(
<T,>(key: string, value: T) => service.set<T>(namespace, key, value),
[service, namespace]
);
const del = useCallback(
(key: string) => service.delete(namespace, key),
[service, namespace]
);
const list = useCallback(() => service.list(namespace), [service, namespace]);
const query = useCallback(
<T,>(predicate: (item: T) => boolean) => service.query<T>(namespace, predicate),
[service, namespace]
);
const clear = useCallback(() => service.clear(namespace), [service, namespace]);
const exportAll = useCallback(() => service.export(namespace), [service, namespace]);
const importAll = useCallback(
(data: Record<string, unknown>) => service.import(namespace, data),
[service, namespace]
);
return useMemo(
() => ({ get, set, delete: del, list, query, clear, exportAll, importAll }),
[get, set, del, list, query, clear, exportAll, importAll]
);
}