PWA App Builder
Verwandeln Sie eine Projektidee in eine App, die ab Tag eins echt ist: läuft lokal, installiert auf einem Handy, arbeitet offline, sendet Benachrichtigungen und kann mit einem öffentlichen Link geteilt werden. Der Stack unten ist bewusst festgelegt – es ist die einzige Kombination, die unter den Host-Einschränkungen dieser Projekte überlebt (kein Compiler, ~300 MB RAM, kein Postgres/MongoDB, kein sudo). Was sich von Projekt zu Projekt ändert, ist die Domäne; was bleibt, ist das Skelett.
Lesen Sie diese ganze Datei, bevor Sie etwas tun. Arbeiten Sie dann die Phasen der Reihe nach ab – sie haben Tore.
0. Der Stack (nicht verhandelbar)
| Schicht | Wahl | Warum dies und nicht die offensichtliche Alternative |
|---|---|---|
| Backend | Express 4, CommonJS, 'use strict' | Ein Prozess bedient API + gebaute UI + Bilder → kein CORS, eine Sache zum Neustarten, geringster Speicher |
| Datenbank | node:sqlite (DatabaseSync) | In Node ≥22.5 eingebaut. Keine nativen Module. better-sqlite3 kann nicht einmal installiert werden (kein gcc) |
| Passwörter | crypto.scrypt + timingSafeEqual | Kein bcrypt (nativ). Niemals Klartext speichern |
| Sitzungen | HMAC-signiertes Token in einem HttpOnly-Cookie | Keine jsonwebtoken-Abhängigkeit, keine localStorage-Exposition gegenüber XSS |
| Frontend | React 18 + Vite 5 + Tailwind 3, gebaut in server/public | Schneller Low-Memory-Build, statische Ausgabe von Express bedient, kein SSR nötig |
| PWA | handgeschriebenes sw.js + manifest.webmanifest | Kein Workbox / vite-plugin-pwa; volle Kontrolle über die Cache-Strategie |
| Push | web-push + lokal generierte VAPID-Schlüssel | Kostenlos, kein Firebase-Konto |
| Bilder | im Browser mit Canvas vor dem Hochladen komprimiert | Kein sharp/multer (nativ), weniger Server-RAM |
| i18n | kleines hauseigenes Wörterbuch, kein i18next | Sofortiges RTL/LTR-Umschalten, winziges Bundle |
Fügen Sie niemals hinzu: better-sqlite3, mongodb, pg, bcrypt, argon2, jsonwebtoken, sharp, canvas, multer, i18next, Workbox, vite-plugin-pwa, socket.io oder irgendein Paket mit nativem Code. Wenn eine Aufgabe eines zu benötigen scheint, lösen Sie es mit der Standardbibliothek oder im Browser.
1. Phase 0 – Den Host erkunden (zuerst erledigen)
bash <skill>/scripts/check-host.sh # node, Compiler, RAM, Swap, CPUs, Ports, cloudflared
Es gibt ein Urteil aus. Zwei Dinge, die Sie in Ihren Plan übernehmen müssen:
- Kein Compiler → Die Nur-JS-Regel oben ist eine harte Tatsache, keine Präferenz.
- Niedrige Ressourcen (
⚠️ NIEDRIGE RESSOURCEN) →npm installundnpm run buildmüssen im Hintergrund mit einer Logdatei ausgeführt werden, die Sie abfragen; ein langer Vordergrund-Befehl wird gekillt. Siehereferences/host-constraints.md.
Browser-Regel (wichtig, und sie ist bedingt)
Standardmäßig mit curl und dem API-Smoke-Test prüfen – das ist schneller und günstiger. Aber die Regel ist "Starten Sie keinen Browser ohne Erlaubnis zu fragen", nicht "niemals einen starten":
-
Auf einem komfortablen Host (≥4 CPUs, Swap vorhanden, viel freier RAM): Fragen ist eine Formalität. Sagen Sie, dass Sie einen kopflosen Browser öffnen möchten, um das gerenderte UI zu überprüfen, und lassen Sie den Benutzer entscheiden.
-
Auf einem ressourcenarmen Host (wie 2 vCPU / ~300 MB / kein Swap): Sagen Sie dem Benutzer warum, im selben Atemzug wie die Anfrage. Eine Chromium-Instanz kann die gesamte Maschine verbrauchen, den Server OOM-killen und einen Neustart erzwingen. Etwa so:
"Für eine visuelle Überprüfung der Oberfläche? Das Starten des Browsers auf diesem Server (2 Kerne und kein Swap) könnte die Ressourcen vollständig aufbrauchen und den Server zum Absturz bringen, was einen Neustart erfordert. Ich überprüfe stattdessen mit
curlund API-Tests, oder bevorzugen Sie, dass ich den Browser starte?"
Respektieren Sie dann die Antwort. Starten Sie niemals einen Browser lautlos.
2. Phase 1 – Die Idee verstehen, dann den Benutzer interviewen (hartes Tor)
2a. Wiederholen Sie, was Sie verstanden haben – in 5 Zeilen, nicht 50
Behandeln Sie: wer es nutzt, die Kernschleife (die Aktion, die sie am meisten wiederholen), die Daten, die sie speichern, und wie "fertig" für eine erste Version aussieht. Planen Sie noch keine Architektur.
2b. Vor dem Bauen nach Präferenzen fragen – das ist erforderlich, nicht optional
Der Benutzer weiß, was er sehen möchte, lange bevor er weiß, was ein Service Worker ist. Diese Antworten im Voraus zu bekommen, ist der Unterschied zwischen einer App, die sie beim ersten Mal lieben, und drei Runden "ändern Sie die Farben". Verwenden Sie das system_ask_user-Tool, damit der Benutzer mit einem Tipp antworten kann – maximal 5 Fragen, jede mit genau 3 Optionen. Wählen Sie diejenigen aus, die den Bau am meisten verändern; überspringen Sie, was Sie vernünftigerweise selbst ableiten oder entscheiden können.
Fragenkatalog (passen Sie die Formulierung an die Domäne des Projekts an; fragen Sie in der Sprache des Benutzers):
| # | Frage | Optionen |
|---|---|---|
| 1 | Standard-Oberflächensprache | Arabisch (RTL) mit EN-Umschaltung · Englisch (LTR) mit AR-Umschaltung · Nur Arabisch |
| 2 | Farbidentität | Warm (Orange/Bernstein) · Ruhig (Türkis/Blau) · Edel (Violett/Indigo) – oder je nach Projektdomäne |
| 3 | Design-Stimmung | Schlicht, praktisch und informationsdicht · Modern mit abgerundeten Ecken und Animationen · Standardmäßig elegantes Dunkel |
| 4 | Mobile-First- oder Desktop-Layout | Mobile App mit unterer Leiste · Desktop-Dashboard mit Seitenleiste · Beides (Standard responsiv) |
| 5 | Konten | Registrierung + Gastmodus ohne Registrierung · Nur Gast (Upgrade später) · Gar keine Konten |
| 6 | Benachrichtigungen | Geplante Alarme + Push · Nur In-App-Benachrichtigungen · Keine Benachrichtigungen |
| 7 | Vorbereitete öffentliche Inhalte | Inhaltskatalog aus JSON-Dateien · Nur Benutzerinhalte · Später |
| 8 | Name und Logo | Arabischer + englischer Name mit Emoji · Ein Name mit gezeichneter Ikone · Du wählst das Beste |
Regeln für das Interview: Fragen Sie nie mehr als 5; fragen Sie nie etwas, das Sie mit gutem Geschmack entscheiden können (Abstände, Animationskurve); wenn der Benutzer „Wähle du“ sagt, entscheiden Sie und machen Sie weiter – fragen Sie nicht erneut. Notieren Sie die Antworten: Sie werden zu den Gerüst-Flags in Phase 3.
2c. Antworten Sie mit dem Plan und warten Sie
Geben Sie einen kurzen Plan (Stack bereits entschieden; Bildschirme; Datenmodell in einer Zeile; die Phasen) und halten Sie an. Die meisten Benutzer in diesem Workflow möchten zustimmen, bevor Code geschrieben wird – eine einzeilige „Einverstanden, los geht's“ ist mehr wert als ein schneller falscher Build.
3. Phase 2 – Die Domäne entwerfen (klein, konkret)
Bevor Sie Code schreiben, notieren Sie im Chat:
- Entitäten + Felder – jedes Feld, das die Kernschleife des Benutzers benötigt; markieren Sie erforderlich vs. optional. Halten Sie die erforderlichen Felder auf das absolute Minimum (ein Name und eine Kategorie schlagen ein Zehn-Felder-Formular).
- Bildschirme – listen Sie sie auf; jeder Bildschirm wird einer Datei in
web/src/pages/zugeordnet. - Routen – eine REST-Gruppe pro Entität plus Authentifizierung.
- Welche optionalen Module zutreffen – Konten/Gast, Alarme+Push, öffentliche Freigabelinks, öffentlicher Inhaltskatalog. Jedes ist bereits in den Vorlagen implementiert; Sie wählen, nicht erfinden.
4. Phase 3 – Gerüst bauen (ein Befehl, dann prüfen)
node <skill>/scripts/scaffold.mjs \
--dir <workspace> --name "Applikationsname" --name-en "AppName" \
--slug appname --prefix ap --palette orange --ink warm [--with-catalog]
Dies erzeugt ~68 Dateien: das voll funktionsfähige Skelett (Auth, eine Demo-CRUD-Entität, PWA-Shell, Push, i18n, UI-Kit, Betriebsskripte) mit der App-Identität, dem Cookie-Präfix und der Markenpalette, die bereits überall ersetzt wurden. Paletten: orange amber rose violet indigo sky teal emerald; Inks: warm cool stone.
Dann, bevor Sie irgendetwas anderes anfassen – beweisen Sie, dass die Pipeline funktioniert:
export PATH="$HOME/node-v24.20.0-linux-x64/bin:$PATH" # Node ist auf diesen Hosts nicht im PATH
npm install # Low-RAM-Host? Im Hintergrund mit Log ausführen und abfragen
npm run build
./scripts/run.sh start
curl -s http://127.0.0.1:3000/api/health
npm run test:api # erwartet "110 bestanden, 2 fehlgeschlagen" bei einem frischen Demo-Gerüst
Die 2 Fehler sind die Katalog-Assertionen, die echte Bilddateien benötigen (npm run catalog:images lädt sie herunter; benötigt Netzwerk). Alles andere muss grün sein, bevor Sie beginnen, die Domäne zu ändern – sonst werden Sie nicht wissen, ob ein späterer Fehler von Ihnen stammt.
Lesen Sie references/templates-guide.md für eine Beschreibung jeder erzeugten Datei und welche Teile die Demo-Domäne sind, die Sie gleich ersetzen werden.
5. Phase 4 – Die Demo-Domäne durch die echte ersetzen
Das Gerüst enthält ein vollständiges Arbeitsbeispiel (eine Mahlzeiten-App), genau damit Sie seine Form kopieren können. Arbeiten Sie von der Datenschicht nach außen, damit nichts in der Luft hängt:
server/db.js– Schreiben Sie die Demo-Tabellen für Ihre Entitäten um. Immer additiv: neue Tabellen imCREATE TABLE IF NOT EXISTS-Block, neue Spalten an das Migrations-Array angehängt. Dann schreiben Sie die Abfragefunktionen.server/routes/<entity>.js– Kopieren Sieroutes/meals.jsals den kanonischen CRUD-Router (optionalFields, einentoEntity()-Mapper, INSERT/PATCH). Passen Sie den Export-Stil an, wieserver/index.jsihn importiert (module.exports = routervs.{ router }– das Repo ist inkonsistent, überprüfen Sie es, bevor Sie schreiben).- Mounten Sie den Router in
server/index.js; fügen Sie das API-Präfix zu nichts anderem hinzu (SPA-Fallback schließt/apibereits aus). web/src/lib/api.js– eine Methode pro Route. Keinfetchin Seiten oder Komponenten, niemals.web/src/pages/*+ Routen inweb/src/App.jsx.scripts/smoke-test.js– Schreiben Sie die Demo-Assertionen mit den vorhandenen Hilfsfunktionencheck(name, condition, extra)+call(path, {method, body})um. Dies ist Ihr Beweis.
Löschen Sie, was Ihre Domäne nicht benötigt (den Router der Demo-Entität, die Seite, API-Methoden und i18n-Schlüssel), anstatt toten Code herumliegen zu lassen.
6. Phase 5 – Frontend: RTL-first, beide Sprachen, ein Designsystem
- Jeder benutzersichtbare String kommt in sowohl
dict.arals auchdict.eninweb/src/lib/i18n.js, gelesen mitt('key'), Interpolation mit{name}-Platzhaltern. Ein Schlüssel in nur einem Wörterbuch ist ein Fehler. - Verwenden Sie logische Utilities (
start-*/end-*/ps-*/pe-*/ms-*/me-*), damit sowohl RTL als auch LTR funktionieren. Die bewusste Ausnahme: Passworteingaben sinddir="ltr"und verwenden daher physischepr-12/right-3. - Verwenden Sie die Komponentenklassen in
web/src/styles.css(.card,.btn-primary,.input,.label,.chip) und die Primitiven inweb/src/components/ui.jsxwieder, bevor Sie verstreutes Tailwind schreiben. - Das Theme ist klassenbasiert auf
documentElement, inlocalStoragegespeichert und wird von einem Inline-Skript inweb/index.htmlvor dem ersten Paint angewandt (verhindert das Flackern und repariert die iOS-Statusleiste). - Responsiv: Mobile-First mit einer unteren Navigation, die ab
md:zu einer Seitenleiste wird (AppShell.jsx). - Überprüfen Sie RTL/LTR bei: Formularen, Listen, der App-Leiste, Modalen und der Toast-Position.
7. Phase 6 – PWA + Benachrichtigungen
sw.js und manifest.webmanifest sind vorhanden. Zwei Dinge, die Sie nicht vergessen dürfen:
- Erhöhen Sie
VERSIONinweb/public/sw.jsjedes Mal, wenn Sie diese Datei ändern, sonst behalten installierte Clients den veralteten Cache für immer. - VAPID-Schlüssel werden beim ersten Start in
data/vapid.jsongeneriert. Der VAPIDsubmuss eine echte auflösbare Domäne sein (mailto:[email protected]) – Apple lehnt*.local/@localhostmit403 BadJwtTokenab, während Google es akzeptiert, was den klassischen "funktioniert auf Android, scheitert still auf iPhone"-Effekt erzeugt. Überschreiben Sie mitVAPID_SUBJECT; niemals eine persönliche Adresse hartcodieren. - Melden Sie Push-Erfolg niemals ohne die tatsächliche Antwort des Anbieters:
sendToUsergibt{total, sent, failed:[{status, reason}]}zurück und entfernt tote Abonnements (404/410/403). - iOS erfordert, dass die App auf dem Startbildschirm installiert wird und die Berechtigung von einem Tap angefordert wird. Halten Sie den In-App-Lokalbenachrichtigungs-Fallback (
useAlarmWatcherinApp.jsx) funktionsfähig.
Details und die Plattformlimits (Bilder in Benachrichtigungen, Statusleistenfarbe, Standalone-Letterboxing) finden Sie in references/pwa-and-push.md – lesen Sie es, bevor Sie etwas zu iOS versprechen.
8. Phase 7 – Verifizieren (dies ist der Beweis der Lieferung)
npm run test:api # isolierte Daten/test.db auf Port 3100, Live-DB unberührt
npm run build && ./scripts/run.sh restart
curl -s http://127.0.0.1:3000/api/health
curl -s http://127.0.0.1:3000/ | head -3 # die gebaute SPA wird ausgeliefert
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/manifest.webmanifest
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/sw.js
Üben Sie auch den echten Benutzerpfad mit curl (Registrierung/Gast → Erstellen → Lesen → Aktualisieren → Löschen), damit Sie echte Ausgabe melden können, nicht "sollte funktionieren". Wenn dann ein Browser erlaubt ist, verwenden Sie ihn für die visuelle Prüfung auf einem handygroßen Viewport.
Melden Sie die genauen Befehle und ihre tatsächliche Ausgabe. Wenn etwas fehlgeschlagen ist, sagen Sie es mit dem Fehler.
9. Phase 8 – Ausliefern
-
Lokales Git-Repo + erster Commit (
git init -b main), damit es einen bekannten guten Zustand gibt, zu dem Sie vor jedem riskanten Experiment zurückkehren können. Niemalspushdrücken, es sei denn, es wird darum gebeten. Conventional Commits mit einem arabischen Betreff:feat(meals): إضافة فلتر الفئات. -
Öffentlicher Link über den Cloudflare Quick Tunnel (
./scripts/tunnel.sh start, dann die URL austunnel.loglesen). Dieser Schritt ist optional und benötigt zwei separate Genehmigungen:- Fragen Sie, ob sie überhaupt einen öffentlichen Link möchten. Wenn sie bereits eine eigene Domain, einen Reverse Proxy oder ein Hosting haben, auf das sie deployen können, brauchen sie keinen Tunnel – drängen Sie keinen auf.
- Überprüfen Sie
cloudflared, bevor Sie etwas versprechen (scripts/check-host.shmeldet es). Wenn es fehlt, sagen Sie es und bitten Sie um Erlaubnis, es zu installieren, bevor Sie ein Installationsprogramm ausführen; installieren Sie niemals ein Binärprogramm still. Bieten Siebrew install cloudflared, den offiziellen Installer oder das Herunterladen der Binärdatei an.
Das Tunnel-Skript richtet eine öffentliche URL ein, die den Entwicklungs-Express-Server auf Port 3000 erreicht. Es macht die App NICHT produktionsbereit – es ist eine Vorschau. Die Zustimmung des Benutzers zu bekommen, dass dies eine Staging-Preview und keine Produktion ist, ist der dritte, informelle Gate.
10. Nachlieferung (optional, aber bringen Sie es NICHT vor Abschluss der unteren Phasen zur Sprache)
Sagen Sie nie „Möchten Sie, dass ich <coole Funktionalität X> hinzufüge?", bevor die App funktioniert. Bleiben Sie diszipliniert: 90 % der Projekte brauchen nur das Skelett und die Domäne – mehr ist Lärm. Wenn die App läuft und Sie noch Zeit im Kontext haben (es gibt kein zweites Projekt), können Sie Folgendes anbieten:
- Einrichtung eines Cron-Jobs für periodische Aufgaben (Hintergrund-Benachrichtigungen, Datenbereinigung). Kein echter Job-Scheduler (kein
cron/atauf diesen Hosts); einsetTimeout-Loop mit Persistenz in der Datenbank. - Einrichtung eines GitHub-Repositorys + CI/CD.
- Docker-Compose-Datei für die lokale Entwicklung mit Hot Reload.
Aber nur, wenn die unteren Phasen abgeschlossen sind und der Benutzer zufrieden ist.
Referenzen
| Datei | Wofür |
|---|---|
references/host-constraints.md | Host-Limits, Ausweichmanöver für Low-RAM-Installationen, Log-Polling |
references/templates-guide.md | Karte der ~68 erzeugten Dateien, welche Teile das Gerüst sind, welche die Demo-Domäne |
references/pwa-and-push.md | iOS vs. Android PWA-Unterschiede, Statusleiste, Symbole, Push-Limits, Debugging |
references/auth-sessions.md | Session-Ablauf, Passwort-Vergessen-Flow, Überschreiben des HMAC-Geheimnisses |
references/preferences.md | Vollständige Liste der Gerüst-Optionen, Auswirkungen jeder Palette/Ink auf Tailwind-Klassen |
Anhang: Zusammenspiel der Skripte
flowchart TD
A[Benutzeridee] --> B[check-host.sh]
B --> C[scaffold.mjs → ~68 Dateien]
C --> D[npm install + build bestätigt]
D --> E[Domänenersetzung: db, routes, api, pages, tests]
E --> F[test:api grün]
F --> G[git init -b main + erster Commit]
G --> H[tunnel.sh öffentliche Vorschau]
H --> I[Auslieferung abgeschlossen]
style C fill:#d4edda,stroke:#155724
style F fill:#d4edda,stroke:#155724
style I fill:#d4edda,stroke:#155724
Erstellt von Ahmed Attia · Version 1.1.1 · MIT-Lizenz