Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/arah.app/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Ará (App Flutter)
# Arah (App Flutter)

App mobile **território-first** e **comunidade-first**. Nome: **Ará**. Interface clean, fundo escuro padrão. Conecta ao **BFF** do repositório.
App mobile **território-first** e **comunidade-first**. Marca: **Arah**. Interface alinhada ao design system (fundo escuro, tipografia Inter, tokens compartilhados). Conecta ao **BFF** do repositório.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use territory terminology in the intro sentence.

Line 3 uses território-first, which breaks the repository glossary standard for geographic terminology in documentation.

Suggested patch
-App mobile **território-first** e **comunidade-first**. Marca: **Arah**. Interface alinhada ao design system (fundo escuro, tipografia Inter, tokens compartilhados). Conecta ao **BFF** do repositório.
+App mobile **territory-first** e **comunidade-first**. Marca: **Arah**. Interface alinhada ao design system (fundo escuro, tipografia Inter, tokens compartilhados). Conecta ao **BFF** do repositório.

As per coding guidelines, use 'territory' (not 'place', 'location', or other variations) as the consistent term for geographic areas in all code and documentation.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
App mobile **território-first** e **comunidade-first**. Marca: **Arah**. Interface alinhada ao design system (fundo escuro, tipografia Inter, tokens compartilhados). Conecta ao **BFF** do repositório.
App mobile **territory-first** e **comunidade-first**. Marca: **Arah**. Interface alinhada ao design system (fundo escuro, tipografia Inter, tokens compartilhados). Conecta ao **BFF** do repositório.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/arah.app/README.md` at line 3, The README intro sentence on line 3
uses the Portuguese term `território-first` which violates the repository's
glossary standard for geographic terminology. Replace `território-first` with
`territory-first` to align with the coding guidelines that mandate using the
English term `territory` as the consistent keyword for geographic areas
throughout all code and documentation.

Source: Coding guidelines


**Fluxo:** Login → Onboarding (escolha de território) ou Home → Feed / Explorar / Publicar / Perfil.

Expand Down
13 changes: 13 additions & 0 deletions frontend/arah.app/assets/images/arah-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/arah.app/docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Arquitetura – Ará App (Flutter)
# Arquitetura – Arah App (Flutter)

Visão da arquitetura do app: rede, estado, rotas e internacionalização.

Expand Down
2 changes: 1 addition & 1 deletion frontend/arah.app/docs/MAPA_PINS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Mapa e pins – App Ará
# Mapa e pins – App Arah

Implementação e opções de tiles (OpenStreetMap, Mapbox).

Expand Down
2 changes: 1 addition & 1 deletion frontend/arah.app/docs/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Documentação do app Ará
# Documentação do app Arah

Documentação interna do app Flutter (frontend/Arah.app).

Expand Down
3 changes: 2 additions & 1 deletion frontend/arah.app/lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'app_router.dart';
import 'core/services/device_registration_listener.dart';
import 'core/config/brand_config.dart';
import 'core/theme/app_theme.dart';
import 'l10n/app_localizations.dart';

Expand All @@ -13,7 +14,7 @@ class ArahApp extends ConsumerWidget {
final router = ref.watch(goRouterProvider);
return DeviceRegistrationListener(
child: MaterialApp.router(
title: 'Ará',
title: BrandConfig.name,
debugShowCheckedModeBanner: false,
theme: AppTheme.light,
darkTheme: AppTheme.dark,
Expand Down
3 changes: 2 additions & 1 deletion frontend/arah.app/lib/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';

import 'core/config/app_config.dart';
import 'core/providers/territory_provider.dart';
import 'core/widgets/arah_scaffold.dart';
import 'features/auth/presentation/screens/login_screen.dart';
import 'features/auth/presentation/providers/auth_state_provider.dart';
import 'features/home/presentation/screens/main_shell_screen.dart';
Expand Down Expand Up @@ -134,7 +135,7 @@ class _SplashOrRedirect extends StatelessWidget {

@override
Widget build(BuildContext context) {
return const Scaffold(
return const ArahScaffold(
body: Center(child: CircularProgressIndicator()),
);
}
Expand Down
10 changes: 10 additions & 0 deletions frontend/arah.app/lib/core/config/brand_config.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// Marca e metadados do ecossistema Arah (espelho de frontend/shared/config/brand.ts).
class BrandConfig {
BrandConfig._();

static const String name = 'Arah';
static const String tagline = 'Território primeiro. Comunidade primeiro.';
static const String description =
'Plataforma digital comunitária orientada ao território.';
static const String siteUrl = 'https://arah.app';
}
12 changes: 8 additions & 4 deletions frontend/arah.app/lib/core/config/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class AppConstants {
static const double spacingMd = 16.0;
static const double spacingLg = 24.0;
static const double spacingXl = 32.0;
static const double spacing2xl = 48.0;
static const double radiusSm = 8.0;
static const double radiusMd = 12.0;
static const double radiusLg = 16.0;
Expand All @@ -29,8 +30,11 @@ class AppConstants {
static const double minTouchTargetSize = 44.0;
static const int defaultPageSize = 20;
static const int maxPageSize = 50;
static const String keyAccessToken = 'araponga_access_token';
static const String keyRefreshToken = 'araponga_refresh_token';
static const String keyTokenExpiry = 'araponga_token_expiry';
static const String keySelectedTerritoryId = 'araponga_selected_territory_id';
static const String keyAccessToken = 'arah_access_token';
static const String keyRefreshToken = 'arah_refresh_token';
static const String keyTokenExpiry = 'arah_token_expiry';
static const String keySelectedTerritoryId = 'arah_selected_territory_id';

/// Pacote para user-agent de mapas (OpenStreetMap).
static const String mapUserAgentPackage = 'com.arah.app';
}
49 changes: 49 additions & 0 deletions frontend/arah.app/lib/core/storage/storage_migration.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../config/constants.dart';

/// Migra chaves legadas `araponga_*` para `arah_*` (uma vez por instalação).
class StorageMigration {
StorageMigration._();

static const _migrationFlag = 'arah_storage_migrated_v1';

static const _secureKeyPairs = <({String legacy, String current})>[
(legacy: 'araponga_access_token', current: AppConstants.keyAccessToken),
(legacy: 'araponga_refresh_token', current: AppConstants.keyRefreshToken),
(legacy: 'araponga_token_expiry', current: AppConstants.keyTokenExpiry),
];

static Future<void> migrateIfNeeded() async {
final prefs = await SharedPreferences.getInstance();
if (prefs.getBool(_migrationFlag) == true) return;

const secureStorage = FlutterSecureStorage(
aOptions: AndroidOptions(encryptedSharedPreferences: true),
);

try {
for (final pair in _secureKeyPairs) {
final legacyValue = await secureStorage.read(key: pair.legacy);
if (legacyValue == null) continue;
final currentValue = await secureStorage.read(key: pair.current);
if (currentValue == null) {
await secureStorage.write(key: pair.current, value: legacyValue);
}
await secureStorage.delete(key: pair.legacy);
}
} catch (_) {
// Secure storage indisponível (ex.: testes unitários sem plugin).
}
Comment on lines +26 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t finalize migration after a secure-storage failure.

Line 47 sets the one-time flag even when Lines 26-38 catch secure-storage errors. That prevents retry on next launch and can leave legacy auth keys unmigrated, causing avoidable session loss.

Suggested patch
-    try {
+    var secureMigrationSucceeded = true;
+    try {
       for (final pair in _secureKeyPairs) {
         final legacyValue = await secureStorage.read(key: pair.legacy);
         if (legacyValue == null) continue;
         final currentValue = await secureStorage.read(key: pair.current);
         if (currentValue == null) {
           await secureStorage.write(key: pair.current, value: legacyValue);
         }
         await secureStorage.delete(key: pair.legacy);
       }
     } catch (_) {
       // Secure storage indisponível (ex.: testes unitários sem plugin).
+      secureMigrationSucceeded = false;
     }
@@
-    await prefs.setBool(_migrationFlag, true);
+    if (secureMigrationSucceeded) {
+      await prefs.setBool(_migrationFlag, true);
+    }

Also applies to: 47-47

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/arah.app/lib/core/storage/storage_migration.dart` around lines 26 -
38, The secure storage migration in the try-catch block (lines 26-38) silently
catches all exceptions but the one-time completion flag at line 47 is still
being set unconditionally, which prevents retry attempts on the next launch if
the migration fails. Move the flag-setting logic that marks the migration as
complete so it only executes when the migration succeeds in the try block, not
after the catch block. This ensures that if secure storage operations fail, the
flag remains unset and the migration will be retried on the next application
launch.


const legacyTerritoryKey = 'araponga_selected_territory_id';
final legacyTerritory = prefs.getString(legacyTerritoryKey);
if (legacyTerritory != null && prefs.getString(AppConstants.keySelectedTerritoryId) == null) {
await prefs.setString(AppConstants.keySelectedTerritoryId, legacyTerritory);
}
await prefs.remove(legacyTerritoryKey);

await prefs.setBool(_migrationFlag, true);
}
}
Loading
Loading