mod login signin design

This commit is contained in:
2026-01-26 12:46:17 +01:00
parent d5b8df9506
commit 3990a8a34e
10 changed files with 305 additions and 93 deletions

View File

@@ -1,68 +1,50 @@
# Backend-Proxy Setup - Deployment Anleitung # Proxy Server Deployment - Anleitung
## 📋 Übersicht ## 📋 Übersicht
Diese Anleitung erklärt, wie Sie die Appwrite Function für Geocoding deployen, um CORS-Probleme zu vermeiden. Diese Anleitung erklärt, wie Sie den Reverse Proxy Server für PTV API Geocoding deployen. Der Proxy umgeht CORS-Probleme und läuft als eigenständiger Container.
## 🚀 Deployment Schritte ## 🏗️ Architektur
### 1. Appwrite Console öffnen ```
Browser (Flutter Web App)
Proxy Server (localhost:3000 / your-server.com:3000)
PTV Geocoding API (api.myptv.com)
```
Navigieren Sie zu Ihrer Appwrite Console: ## 🚀 Lokale Entwicklung
`https://appwrite.joshihomeserver.ipv64.net/console`
### 2. Function erstellen ### 1. Proxy Server starten
1. Klicken Sie auf **Functions** im Menü
2. Klicken Sie auf **Create Function**
3. Füllen Sie die Details aus:
- **Name**: `geocode-location`
- **Function ID**: Wird automatisch generiert (z.B. `65a123456789abc`)
- **Runtime**: Wählen Sie `Node.js 18.0` oder höher
- **Execute Access**: `Any` (damit alle eingeloggten User die Function nutzen können)
### 3. Code hochladen
**Option A: Über die Console**
1. Gehen Sie zum Tab **Deployment**
2. Erstellen Sie ein neues Deployment
3. Wählen Sie **Manual** als Deployment-Methode
4. Laden Sie folgende Dateien hoch:
- `appwrite_functions/geocode-location/main.js`
- `appwrite_functions/geocode-location/package.json`
5. Setzen Sie **Entrypoint**: `main.js`
6. Klicken Sie auf **Deploy**
**Option B: Über CLI** (wenn Appwrite CLI installiert)
```bash ```bash
cd /home/digitalman/Development/flutter_tank_web_app cd /home/digitalman/Development/flutter_tank_web_app
appwrite deploy function
# Option A: Mit Script
./start-proxy.sh
# Option B: Manuell
cd proxy-server
node server.js
``` ```
### 4. Function ID in Flutter App eintragen Der Proxy läuft auf `http://localhost:3000`
1. Nach erfolgreichem Deployment kopieren Sie die **Function ID** ### 2. Flutter App starten
2. Öffnen Sie `lib/config/environment.dart`
3. Ersetzen Sie `YOUR_FUNCTION_ID_HERE` mit Ihrer Function ID:
```dart ```bash
static const String appwriteGeocodeFunctionId = '65a123456789abc'; // Ihre ID hier flutter run -d chrome
``` ```
### 5. Testen ### 3. Testen
**In der Appwrite Console:** **Geocoding Request:**
1. Gehen Sie zu Ihrer Function ```bash
2. Klicken Sie auf **Execute** curl "http://localhost:3000/?lat=47.9385165&lon=13.762887&apiKey=YOUR_API_KEY"
3. Verwenden Sie diesen Test-Body:
```json
{
"lat": 47.9385165,
"lon": 13.762887,
"apiKey": "NTYxMDQ3NTY2OWI3NDI5ZGIzZWIxOWNiNTNhMDEwODY6YTQ4MTJhYzYtYmYzOC00ZmE4LTk4YzYtZDBjNzYyZTAyNjBk"
}
``` ```
4. Erwartete Response:
**Erwartete Response:**
```json ```json
{ {
"success": true, "success": true,
@@ -74,44 +56,273 @@ static const String appwriteGeocodeFunctionId = '65a123456789abc'; // Ihre ID hi
} }
``` ```
**In der Flutter App:** **Health Check:**
1. Starten Sie die App neu ```bash
2. Erstellen Sie einen neuen Tankeintrag curl http://localhost:3000/health
3. Die Standortabfrage sollte nun über den Backend-Proxy laufen # Response: healthy
4. Sie sollten eine Erfolgs-Snackbar mit der Adresse sehen ```
## 🐳 Docker Deployment (Empfohlen)
### 1. Docker Images bauen
```bash
# Interaktives Deployment-Script
./deploy.sh
# Wählen Sie Option 3: "Alles bauen und starten"
# Oder manuell
docker-compose up -d --build
```
### 2. Services überprüfen
```bash
docker-compose ps
# Erwartete Ausgabe:
# flutter-tank-web Up 0.0.0.0:8090->80/tcp
# ptv-proxy Up 0.0.0.0:3000->3000/tcp
```
### 3. Logs prüfen
```bash
# Proxy Logs
docker-compose logs -f ptv-proxy
# Alle Services
docker-compose logs -f
```
## 🌐 Produktion - Auf Server deployen
### Schritt 1: Server vorbereiten
**SSH zum Server:**
```bash
ssh user@your-server.com
```
**Docker installieren (falls nicht vorhanden):**
```bash
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
```
### Schritt 2: Code auf Server kopieren
**Option A: Git**
```bash
git clone https://github.com/your-repo/flutter_tank_web_app.git
cd flutter_tank_web_app
```
**Option B: SCP/Rsync**
```bash
# Von lokalem Rechner
rsync -avz --exclude 'build' --exclude '.dart_tool' \
. user@your-server.com:/opt/flutter-tank-app/
```
### Schritt 3: Proxy URL konfigurieren
Bearbeiten Sie `lib/config/environment.dart`:
```dart
class Environment {
// Produktions-URL des Proxy Servers
static const String localProxyUrl = 'http://your-server.com:3000';
static const bool useLocalProxy = true;
// ... rest bleibt gleich
}
```
### Schritt 4: Neu builden und deployen
```bash
cd /opt/flutter-tank-app
./deploy.sh
# Option 3: "Alles bauen und starten"
```
### Schritt 5: Firewall konfigurieren
```bash
# Port 8090 (Web App) und 3000 (Proxy) öffnen
sudo ufw allow 8090/tcp
sudo ufw allow 3000/tcp
sudo ufw enable
```
## 🔒 Sichere Konfiguration mit Nginx (Empfohlen)
Statt Port 3000 direkt zu exponieren, verwenden Sie Nginx als Reverse Proxy:
### 1. Nginx konfigurieren
```bash
sudo nano /etc/nginx/sites-available/tank.yourdomain.com
```
```nginx
server {
listen 80;
server_name tank.yourdomain.com;
# Flutter Web App
location / {
proxy_pass http://localhost:8090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# Proxy Server (API Endpoint)
location /api/geocode {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# CORS Headers werden vom Proxy Server gesetzt
proxy_hide_header Access-Control-Allow-Origin;
}
}
```
### 2. Site aktivieren
```bash
sudo ln -s /etc/nginx/sites-available/tanknew.joshihomeserver.ipv64.net /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
### 3. SSL Zertifikat (Let's Encrypt)
```bash
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d tanknew.joshihomeserver.ipv64.net
```
### 4. Environment anpassen
```dart
static const String localProxyUrl = 'https://tanknew.joshihomeserver.ipv64.net/api/geocode';
```
### 5. Firewall anpassen
```bash
# Nur 80 und 443 öffnen (nicht 3000)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw deny 3000/tcp # Proxy nur über Nginx erreichbar
```
## 🔧 Troubleshooting ## 🔧 Troubleshooting
### Function ID nicht gesetzt ### Proxy Server startet nicht
**Problem:** Console-Warnung: "Appwrite Function ID nicht konfiguriert"
**Lösung:** Schritt 4 nochmal durchführen und App neu starten **Logs prüfen:**
```bash
docker-compose logs ptv-proxy
```
**Häufige Probleme:**
- Port 3000 bereits belegt: `sudo lsof -i :3000`
- Node.js nicht installiert: `node --version`
### CORS-Fehler trotz Proxy
**Prüfen:**
1. Ist der Proxy erreichbar? `curl http://localhost:3000/health`
2. Richtige URL in `environment.dart`?
3. Browser Cache leeren und App neu laden
### "Connection refused"
### Function Execution fehlgeschlagen
**Problem:** Status ist nicht "completed"
**Lösung:** **Lösung:**
1. Prüfen Sie die Logs in der Appwrite Console ```bash
2. Stellen Sie sicher, dass die Runtime korrekt ist # Docker Container laufen?
3. Prüfen Sie ob alle Dateien hochgeladen wurden docker-compose ps
### PTV API Fehler # Proxy neu starten
**Problem:** "PTV API Fehler - Status Code: 401" docker-compose restart ptv-proxy
```
### PTV API gibt 401 zurück
**Problem:** Ungültiger API Key
**Lösung:** API Key in `environment.dart` überprüfen **Lösung:** API Key in `environment.dart` überprüfen
### CORS weiterhin ein Problem ### Im Container: "npm not found"
**Problem:** Immer noch CORS-Fehler
**Problem:** Lokales `node_modules` committet
**Lösung:** **Lösung:**
1. Stellen Sie sicher, dass die alte `getNearbyLocation` Methode nicht mehr verwendet wird ```bash
2. Prüfen Sie, dass `appwriteService.geocodeLocation` aufgerufen wird # .dockerignore prüfen
3. Cachen leeren und App neu builden cat .dockerignore | grep node_modules
# Sollte vorhanden sein
```
## 📊 Monitoring
### Service Status
```bash
# Docker
docker-compose ps
# System Resources
docker stats
# Health Check
curl http://localhost:3000/health
```
### Logs Live anschauen
```bash
# Proxy
docker-compose logs -f ptv-proxy
# Alle Services
docker-compose logs -f --tail=100
```
## 🔄 Updates deployen
```bash
# Code aktualisieren
git pull
# Container neu bauen und starten
docker-compose up -d --build
# Alte Images aufräumen
docker image prune -f
```
## ✅ Erfolgskriterien ## ✅ Erfolgskriterien
Nach erfolgreichem Deployment sollten Sie: Nach erfolgreichem Deployment sollten Sie:
-Eine Erfolgs-Snackbar mit Adresse sehen (nicht nur Koordinaten) -Proxy Health Check erfolgreich: `curl http://tanknew.joshihomeserver.ipv64.net:3000/health`
-Keine CORS-Fehler mehr in der Browser-Console -Geocoding funktioniert in der App
-In den Logs: "📍 Verwende Backend-Proxy für Geocoding..." -Browser Console zeigt: "🔄 Verwende lokalen Proxy..."
-In den Logs: "✅ Geocoding erfolgreich: [Adresse]" -Browser Console zeigt: "✅ Geocoding erfolgreich (Proxy): [Adresse]"
- ✅ Keine CORS-Fehler mehr
## 📝 Alternative ohne Deployment ## 📝 Produktions-Checkliste
Falls Sie die Function nicht deployen möchten, wird automatisch auf Koordinaten-Speicherung zurückgegriffen. Die App funktioniert weiterhin, speichert aber `Lat: XX.XXXXXX, Lon: YY.YYYYYY` statt der Adresse. - [ ] Docker und Docker Compose installiert
- [ ] Code auf Server übertragen
- [ ] `localProxyUrl` in environment.dart angepasst
- [ ] Docker Containers laufen (`docker-compose ps`)
- [ ] Firewall konfiguriert
- [ ] Nginx Reverse Proxy eingerichtet (empfohlen)
- [ ] SSL Zertifikat installiert
- [ ] Health Checks erfolgreich
- [ ] Geocoding in App getestet

View File

@@ -20,19 +20,21 @@ ENV FLUTTER_HOME=/usr/local/flutter
ENV PATH="${FLUTTER_HOME}/bin:${PATH}" ENV PATH="${FLUTTER_HOME}/bin:${PATH}"
RUN git clone https://github.com/flutter/flutter.git ${FLUTTER_HOME} -b stable --depth 1 && \ RUN git clone https://github.com/flutter/flutter.git ${FLUTTER_HOME} -b stable --depth 1 && \
flutter config --enable-web && \ flutter config --enable-web --no-analytics && \
flutter precache --web flutter doctor -v
# Set working directory # Set working directory
WORKDIR /app WORKDIR /app
# Copy app files # Copy app files
COPY pubspec.yaml pubspec.lock ./ COPY pubspec.yaml pubspec.lock ./
# Run pub get (downloads web dependencies without needing gradle)
RUN flutter pub get RUN flutter pub get
COPY . . COPY . .
# Build web app # Build web app (downloads web artifacts on-demand without gradle)
RUN flutter build web --release --web-renderer canvaskit RUN flutter build web --release --web-renderer canvaskit
# Production stage - Nginx # Production stage - Nginx

View File

@@ -57,7 +57,7 @@ case $option in
echo -e "${GREEN}✅ Services gestartet!${NC}" echo -e "${GREEN}✅ Services gestartet!${NC}"
echo "" echo ""
echo -e "${YELLOW}📡 Verfügbare Endpoints:${NC}" echo -e "${YELLOW}📡 Verfügbare Endpoints:${NC}"
echo -e " Flutter Web App: ${GREEN}http://localhost:8080${NC}" echo -e " Flutter Web App: ${GREEN}http://localhost:8090${NC}"
echo -e " Proxy Server: ${GREEN}http://localhost:3000${NC}" echo -e " Proxy Server: ${GREEN}http://localhost:3000${NC}"
echo "" echo ""
echo -e "${YELLOW}📊 Status prüfen:${NC}" echo -e "${YELLOW}📊 Status prüfen:${NC}"

View File

@@ -1,5 +1,3 @@
version: '3.8'
services: services:
# Flutter Web App # Flutter Web App
flutter-tank-web: flutter-tank-web:
@@ -9,14 +7,14 @@ services:
container_name: flutter-tank-web container_name: flutter-tank-web
restart: unless-stopped restart: unless-stopped
ports: ports:
- "8080:80" - "8090:80"
networks: networks:
- app-network - app-network
environment: environment:
- TZ=Europe/Vienna - TZ=Europe/Vienna
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.flutter-tank.rule=Host(`tank.yourdomain.com`)" - "traefik.http.routers.flutter-tank.rule=Host(`tanknew.joshihomeserver.ipv64.net`)"
- "traefik.http.routers.flutter-tank.entrypoints=websecure" - "traefik.http.routers.flutter-tank.entrypoints=websecure"
- "traefik.http.routers.flutter-tank.tls.certresolver=letsencrypt" - "traefik.http.routers.flutter-tank.tls.certresolver=letsencrypt"
- "traefik.http.services.flutter-tank.loadbalancer.server.port=80" - "traefik.http.services.flutter-tank.loadbalancer.server.port=80"

View File

@@ -244,4 +244,8 @@ class EditController extends GetxController {
locationController.dispose(); locationController.dispose();
super.onClose(); super.onClose();
} }
void gotToList() {
Get.offAllNamed(HomePage.namedRoute);
}
} }

View File

@@ -24,7 +24,7 @@ class EditPage extends GetView<EditController> {
centerTitle: true, centerTitle: true,
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back), icon: const Icon(Icons.arrow_back),
onPressed: () => Get.back(), onPressed: () => editCtrl.gotToList(),
), ),
), ),
body: Container( body: Container(
@@ -266,7 +266,7 @@ class EditPage extends GetView<EditController> {
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: OutlinedButton( child: OutlinedButton(
onPressed: () => Get.back(), onPressed: () => editCtrl.gotToList(),
style: OutlinedButton.styleFrom( style: OutlinedButton.styleFrom(
foregroundColor: Colors.white, foregroundColor: Colors.white,
side: const BorderSide(color: Colors.white, width: 2), side: const BorderSide(color: Colors.white, width: 2),

View File

@@ -19,7 +19,7 @@ class LoginPage extends GetView<LoginController> {
width: displayWidth, width: displayWidth,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 16.0, horizontal: 16.0,
vertical: 130.0, vertical: 100.0,
), ),
color: Colors.blue.shade100, color: Colors.blue.shade100,
child: SingleChildScrollView( child: SingleChildScrollView(

View File

@@ -17,10 +17,7 @@ class SigninPage extends GetView<SigninController> {
body: Container( body: Container(
height: displayHeight, height: displayHeight,
width: displayWidth, width: displayWidth,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 90.0),
horizontal: 16.0,
vertical: 100.0,
),
color: Colors.blue.shade100, color: Colors.blue.shade100,
child: SingleChildScrollView( child: SingleChildScrollView(
child: MySigninWidget( child: MySigninWidget(

View File

@@ -58,8 +58,8 @@ class MyLoginWidget extends StatelessWidget {
borderRadius: BorderRadius.circular(18), borderRadius: BorderRadius.circular(18),
child: Image.asset( child: Image.asset(
'assets/images/guru.png', 'assets/images/guru.png',
width: 400, width: 300,
height: 400, height: 300,
), ),
), ),
), ),

View File

@@ -58,8 +58,8 @@ class MySigninWidget extends StatelessWidget {
borderRadius: BorderRadius.circular(18), borderRadius: BorderRadius.circular(18),
child: Image.asset( child: Image.asset(
'assets/images/guru01.png', 'assets/images/guru01.png',
width: 400, width: 300,
height: 400, height: 300,
), ),
), ),
), ),