Compare commits

..

No commits in common. "17b572441da4f18d422586a3467a4efdc742035a" and "45be22b0b9b33f84a78e0ffead297d9f84204259" have entirely different histories.

1506 changed files with 11964 additions and 64716 deletions

View file

@ -1,62 +1,80 @@
# ai-digest # Ignore everything by default
.aidigestignore *
# versioning # First include the source directory
CHANGELOG.md !src/
.versionrc.json !src/**/
!src/**/*.js
!src/**/*.jsx
!src/**/*.ts
!src/**/*.tsx
# lint # Then exclude specific patterns and directories
.commitlintrc.json # Build and dependencies
.eslintrc.js node_modules/
.editorconfig build/
.husky dist/
coverage/
# node # Platform specific
.yarnrc.yml ios/
.yarn android/
# docker # Configuration files
.dockerignore *.json
docker-compose.build.yaml *.lock
*.yml
*.yaml
*.env*
*.config.*
.*rc*
Dockerfile*
# env # Documentation
.env.local *.md
*.txt
docs/
# devbox # Tests and stories
devbox.lock **/__tests__/
.devbox/ **/*.test.*
**/*.spec.*
**/*.stories.*
e2e/
# git # Generated and utility files
.gitignore *.d.ts
*.map
# tmux
.tmux.conf
.tmuxp.full-decoupled.yaml
.tmuxp.yaml
# md
README.md
# ci/cd
.forgejo
# binaries
*.png
*.svg
*.jpg
*.jpeg
*.ico
# generic
*.bak
*.tmp
*.log *.log
# project # Assets and styles
tileserver-files src/assets/
.dev-secrets **/*.css
.osm-files **/*.scss
osm-files **/*.style.*
tests **/*.styles.*
docs *.svg
dockerfile-x *.png
*.jpg
*.ttf
# Common utility/boilerplate directories
src/i18n/
src/theme/
src/utils/
src/lib/
src/components/
src/navigation/
src/hooks/
src/hoc/
# Auto-generated or index files
**/index.js
**/index.ts
**/constants.js
**/constants.ts
**/types.ts
# Deprecated files
*.bak
*.old

View file

@ -1,5 +0,0 @@
{
"extends": [
"@commitlint/config-conventional"
]
}

View file

@ -1,6 +0,0 @@
{
"crv": "Ed25519",
"d": "NuYqgJxxoFye_uIVcu1FYtpzeXhwCBcTP2od3xAQjFs",
"x": "BIoZ8WwlWgplcYSQKUvlzE9dE8jKEOOvH5_Z19N-2zc",
"kty": "OKP"
}

View file

@ -1,6 +0,0 @@
{
"crv": "Ed25519",
"d": "d3F9wKOVQIWXhDckflJs7KoUvI5mFX9jRCpeEbW4LG8",
"x": "H2MyHfvzAnNtnM6sUOhE32OIPPs-Ix6F13HaZ9fhCrg",
"kty": "OKP"
}

View file

@ -1,23 +1,66 @@
**/*.log .git/
**/*.md # OSX
#
**/.DS_Store **/.DS_Store
**/docker-compose.build.yaml
**/docker-compose.yaml
**/nodemon.json
**/.git
**/.dockerignore
**/Dockerfile
**/Dockerfile.*
**/*.dockerfile
**/node_modules
**/.eslintcache
**/.npm
/.osm-files # Xcode
/osm-files #
/tileserver-files **/build/
**/*.pbxuser
!**/default.pbxuser
**/*.mode1v3
!**/default.mode1v3
**/*.mode2v3
!**/default.mode2v3
**/*.perspectivev3
!**/default.perspectivev3
**/xcuserdata
**/*.xccheckout
**/*.moved-aside
**/DerivedData
**/*.hmap
**/*.ipa
**/*.xcuserstate
**/project.xcworkspace
services/*/build # Android/IntelliJ
services/*/dist #
**/build/
**/.idea
**/.gradle
**/local.properties
**/*.iml
**/*.hprof
**/.cxx/
**/*.keystore
!**/debug.keystore
googleServiceAccountKey.json # node.js
#
**/node_modules/
**/npm-debug.log
**/yarn-error.log
# Bundle artifacts
**/*.jsbundle
# CocoaPods
ios/Pods/
# Temporary files created by Metro to check the health of the file watcher
**/.metro-health-check*
# Expo
**/.expo/
**/web-build/
**/dist/
# Yarn berry
**/.pnp.*
**/.yarn/*
!**/.yarn/patches
!**/.yarn/plugins
!**/.yarn/releases
!**/.yarn/sdks
!**/.yarn/versions
# !.yarn/cache

View file

@ -1,10 +0,0 @@
root = true
[*]
end_of_line = lf
insert_final_newline = false
charset = utf-8
[*.js]
indent_style = space
indent_size = 2

54
.env
View file

@ -1,54 +0,0 @@
# DEV PORTS
API_PORT=4200
WEB_PORT=4203
SERVICE_APP_PORT=4209
FILES_PORT=4292
EXPOSE_API_PORT=4200
EXPOSE_HASURA_PORT=4201
EXPOSE_PG_PORT=4204
EXPOSE_MINO_PORT=4290
EXPOSE_MINIO_PORT=4290
EXPOSE_MINO_CONSOLE_PORT=4291
EXPOSE_MINIO_CONSOLE_PORT=4291
MINIO_ROOT_USER=minio-admin
MINIO_ROOT_PASSWORD=minio-admin
EXPOSE_FILES_PORT=4292
EXPOSE_REDIS_QD_PORT=4278
EXPOSE_REDIS_HG_PORT=4279
EXPOSE_KVROCKS_CG_PORT=4277
EXPOSE_RABBITMQ_NODE_PORT=4272
EXPOSE_RABBITMQ_MANAGEMENT_PORT_PORT=4273
OSRM_CAR_PORT=4261
OSRM_FOOT_PORT=4262
OSRM_BICYCLE_PORT=4263
TILESERVERGL_PORT=4282
NOMINATIM_PORT=4283
HASURA_CONSOLE_PORT=4295
HASURA_CONSOLE_API_PORT=4293
# JWT
CLAIMS_NAMESPACE=https://alertesecours.fr/claims
# APP
APP_OA_FILES_URL=http://10.0.2.2:4292/api/v1/oas
APP_GRAPHQL_URL=http://10.0.2.2:4201/v1/graphql
APP_GRAPHQL_WS_URL=ws://10.0.2.2:4201/v1/graphql
APP_OSRM_CAR_URL=http://10.0.2.2:4261
APP_OSRM_FOOT_URL=http://10.0.2.2:4262
APP_OSRM_BICYCLE_URL=http://10.0.2.2:4263
APP_GEOLOC_SYNC_URL=http://10.0.2.2:4200/api/v1/oas/geoloc/sync
# APP_MAPVIEW_STYLE_URL=https://tiles.alertesecours.fr/styles/basic-preview/style.json
APP_MAPVIEW_STYLE_URL=http://10.0.2.2:4203/app/style.json
# APP_MAPVIEW_STYLE_URL=https://openmaptiles.geo.data.gouv.fr/styles/osm-bright/style.json
# API KEY
WHAT3WORDS_API_KEY=
# GoogleServices
ANDROID_GOOGLE_SERVICES_FILE_PATH=/home/jo/.lab/alertesecours/google-services.json
ANDROID_GOOGLE_SERVICES_FILE_PATH=/home/jo/.lab/alertesecours/GoogleService-Info.plist

View file

@ -1,54 +1,20 @@
# DEV PORTS # Sentry configuration
API_PORT=4200 SENTRY_URL=https://sentry.io
WEB_PORT=4203 SENTRY_DSN=your_sentry_dsn_here
SERVICE_APP_PORT=4209 SENTRY_ORG=your_sentry_org_here
FILES_PORT=4292
EXPOSE_API_PORT=4200 SENTRY_PROJECT=alertesecours-application
EXPOSE_HASURA_PORT=4201 SENTRY_DISABLE_AUTO_UPLOAD=true
EXPOSE_PG_PORT=4204 LOCAL_DEV=true
EXPOSE_MINO_PORT=4290
EXPOSE_MINIO_PORT=4290
EXPOSE_MINO_CONSOLE_PORT=4291
EXPOSE_MINIO_CONSOLE_PORT=4291
MINIO_ROOT_USER=minio-admin
MINIO_ROOT_PASSWORD=minio-admin
EXPOSE_FILES_PORT=4292
EXPOSE_REDIS_QD_PORT=4278
EXPOSE_REDIS_HG_PORT=4279
EXPOSE_KVROCKS_CG_PORT=4277
EXPOSE_RABBITMQ_NODE_PORT=4272 # Android Emulator Configuration
EXPOSE_RABBITMQ_MANAGEMENT_PORT_PORT=4273 ANDROID_EMULATOR_NAME=Pixel_6_API_30
OSRM_CAR_PORT=4261 ASC_API_KEY_ID=
OSRM_FOOT_PORT=4262 ASC_API_ISSUER_ID=
OSRM_BICYCLE_PORT=4263 ASC_API_KEY_PATH=
PROVIDER_ID=
TILESERVERGL_PORT=4282 # Background Geolocation License Keys
NOMINATIM_PORT=4283 BACKGROUND_GEOLOCATION_LICENSE_ANDROID=your_license_key_here
BACKGROUND_GEOLOCATION_LICENSE_IOS=your_license_key_here
HASURA_CONSOLE_PORT=4295
HASURA_CONSOLE_API_PORT=4293
# JWT
CLAIMS_NAMESPACE=https://alertesecours.fr/claims
# APP
APP_OA_FILES_URL=http://10.0.2.2:4292/api/v1/oas
APP_GRAPHQL_URL=http://10.0.2.2:4201/v1/graphql
APP_GRAPHQL_WS_URL=ws://10.0.2.2:4201/v1/graphql
APP_OSRM_CAR_URL=http://10.0.2.2:4261
APP_OSRM_FOOT_URL=http://10.0.2.2:4262
APP_OSRM_BICYCLE_URL=http://10.0.2.2:4263
APP_GEOLOC_SYNC_URL=http://10.0.2.2:4200/api/v1/oas/geoloc/sync
# APP_MAPVIEW_STYLE_URL=https://tiles.alertesecours.fr/styles/basic-preview/style.json
APP_MAPVIEW_STYLE_URL=http://10.0.2.2:4203/app/style.json
# APP_MAPVIEW_STYLE_URL=https://openmaptiles.geo.data.gouv.fr/styles/osm-bright/style.json
# API KEY
WHAT3WORDS_API_KEY=
# GoogleServices
ANDROID_GOOGLE_SERVICES_FILE_PATH=/home/jo/.lab/alertesecours/google-services.json
ANDROID_GOOGLE_SERVICES_FILE_PATH=/home/jo/.lab/alertesecours/GoogleService-Info.plist

17
.envrc
View file

@ -1,2 +1,15 @@
# Automatically load the Devbox environment export PATH=$PWD/bin:$PWD/scripts:$PATH
eval "$(devbox generate direnv --print-envrc)" export PROJECT_WORKINGDIR=$PWD
# appli
export JAVA_HOME=${JAVA_HOME:-"/opt/android-studio/jbr"}
export ANDROID_HOME=$HOME/Android/Sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools
export NODE_OPTIONS"=--openssl-legacy-provider"
# dotenv
dotenv_if_exists .env.default
dotenv_if_exists .env.local

View file

@ -1,111 +1,157 @@
const path = require("path") const path = require("path");
const fs = require("fs")
// see https://github.com/import-js/eslint-plugin-import/issues/1174
const packageDirs = ["libs", "services"]
const packageDir = []
for (const dir of packageDirs) {
for (const d of fs
.readdirSync(path.resolve(__dirname, dir))
.filter(
(entry) =>
entry.slice(0, 1) !== "." &&
fs.lstatSync(path.resolve(__dirname, dir, entry)).isDirectory()
)) {
const p = path.resolve(dir, d)
packageDir.push(p)
}
}
module.exports = { module.exports = {
ignorePatterns: ["**/build/*", "modjo", "**/as-back"], root: true,
settings: { env: {
"import/resolver": { "react-native/react-native": true,
alias: true, jest: true,
},
}, },
extends: [ extends: [
"airbnb-base",
"prettier",
"plugin:prettier/recommended", "plugin:prettier/recommended",
"plugin:import/recommended", "plugin:import/recommended",
"plugin:jsx-a11y/recommended",
"plugin:react-hooks/recommended",
], ],
plugins: ["sql-pretty"], parser: "@babel/eslint-parser",
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 2021,
sourceType: "module",
babelOptions: {
configFile: path.resolve(__dirname, "babel.config.js"),
},
},
plugins: [
"babel",
"sort-keys-fix",
"react",
"react-native",
"react-native-a11y",
"unused-imports",
"autoimport-declarative",
],
settings: {
react: {
version: "detect",
},
"import/ignore": ["react-native"],
"import/resolver": {
// Ensure ESLint can resolve regular JS packages under Yarn PnP as well.
// Without this, some deps (ex: expo-sqlite) may be incorrectly flagged
// by import/no-unresolved even though they're present.
node: {
extensions: [".js", ".jsx", ".ts", ".tsx", ".json"],
},
typescript: {},
},
},
ignorePatterns: ["build", "node_modules", "e2e", "**/*.bak.js"],
rules: { rules: {
"no-undef": [2], "no-undef": [2],
"sql-pretty/format": [1, { tags: ["sql"] }], "react/forbid-prop-types": [0],
"no-shadow": [2, { allow: ["sql", "error"] }], "react/jsx-uses-react": 1,
"node/no-extraneous-require": [0], "react/jsx-uses-vars": 1,
"import/no-commonjs": [0], "react-hooks/exhaustive-deps": "error",
"import/no-dynamic-require": [0], "jsx-a11y/no-autofocus": 0,
"import/no-extraneous-dependencies": [0],
"import/order": [ // React-Native accessibility: start as warnings to enable gradual adoption
"error", // without breaking the build; we will tighten to errors as we fix surfaces.
"react-native-a11y/has-accessibility-hint": "error",
"react-native-a11y/has-valid-accessibility-descriptors": "error",
"import/no-named-as-default": 0,
"import/no-named-as-default-member": 0,
// 'unused-imports/no-unused-imports-ts': 1, # enable and run yarn lint --fix to autoremove all unused imports
"autoimport-declarative/autoimport": [
1,
{ {
groups: [ packages: {
"builtin", react: [
"external", "useState",
"internal", "useEffect",
"parent", "useContext",
"index", "useReducer",
"sibling", "useCallback",
"object", "useMemo",
], "useRef",
pathGroups: [ "useImperativeHandle",
{ "useLayoutEffect",
group: "internal", "useDebugValue",
pattern: "~/**", "createRef",
}, "forwardRef",
{ {
group: "internal", name: "React",
pattern: "~**", isDefault: true,
}, },
], ],
pathGroupsExcludedImportTypes: [], "react-native": [
}, "useWindowDimensions",
], "View",
"global-require": [0], "TouchableOpacity",
"no-restricted-syntax": [0], "TouchableHighlight",
"no-async-promise-executor": [0], "Image",
"no-nested-ternary": [0], "StyleSheet",
"no-loop-func": [0], ],
"no-new": [0], "@react-navigation/native": [
"func-names": [0], "useNavigation",
"no-plusplus": [0], "useFocusEffect",
"no-param-reassign": [0], "useIsFocused",
"no-continue": [0], ],
"no-unused-vars": [ "@maplibre/maplibre-react-native": [
2, {
{ name: "Maplibre",
vars: "all", isDefault: true,
args: "after-used", },
argsIgnorePattern: "^_", ],
varsIgnorePattern: "^_", "@expo/vector-icons": [
}, "MaterialCommunityIcons",
], "MaterialIcons",
"no-console": [0], "Entypo",
"no-throw-literal": [0], "FeatherMaterialIcons",
"no-await-in-loop": [0], ],
"consistent-return": [0], "react-native-paper": ["ToggleButton", "Button", "FAB"],
semi: ["error", "never"], "@apollo/client": ["useQuery", "useMutation", "useLazyQuery"],
"prettier/prettier": [ "react-hook-form": [
"error", "FormProvider",
{ "Controller",
semi: false, "useForm",
}, "useFormContext",
], "useFieldArray",
}, "useField",
parserOptions: { ],
ecmaVersion: "latest", moment: [
sourceType: "script", {
env: [ name: "moment",
{ isDefault: true,
node: true, },
],
"hooks/useStreamQueryWithSubscription": [
{
name: "useStreamQueryWithSubscription",
isDefault: true,
},
],
"~/theme": ["useTheme", "createStyles"],
"~/lib/toast-notifications": ["useToast"],
"~/lib/geo/humanizeDistance": [
{
name: "humanizeDistance",
isDefault: true,
},
],
"~/components/Text": [
{
name: "Text",
isDefault: true,
},
],
},
}, },
], ],
}, },
globals: { globals: {
AggregateError: true, AbortController: true,
dbug: true,
}, },
} };

View file

@ -1,108 +0,0 @@
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
on:
workflow_dispatch:
push:
branches:
- "main"
paths:
- "**"
- "!app/**"
tags:
- "**"
jobs:
build:
outputs:
tags: ${{ steps.meta.outputs.tags }}
runs-on: ubuntu-latest
container:
image: devthefuture/act-runner:latest
volumes:
- /buildkit-certs:/buildkit-certs
strategy:
matrix:
build:
- name: hasura
dockerfile: ./services/hasura/Dockerfile
- name: api
dockerfile: ./services/api/Dockerfile
- name: files
dockerfile: ./services/files/Dockerfile
- name: tasks
dockerfile: ./services/tasks/Dockerfile
- name: watchers
dockerfile: ./services/watchers/Dockerfile
- name: web
dockerfile: ./services/web/Dockerfile
- name: app
dockerfile: ./services/app/Dockerfile
steps:
- name: ⏬ Checkout code repository
uses: actions/checkout@v4
with:
token: ${{ secrets.M8A_ORG_BOT_REPO_TOKEN }} # Required for private repositories to works consistently, avoiding random errors
- name: 📌 Extract metadata (tags, labels) for Docker
id: meta
uses: https://git.devthefuture.org/devthefuture/docker-metadata-action@v5
with:
images: git.devthefuture.org/${{ github.repository }}/${{ matrix.build.name }}
tags: |
type=semver,pattern={{version}},priority=900
type=semver,pattern=v{{version}},priority=900
type=sha,priority=890
type=ref,event=branch,priority=600
type=ref,event=pr,priority=600
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }},priority=200
- name: 📦 Build and push Docker image
uses: https://git.devthefuture.org/devthefuture/actions/buildkit@main
with:
context: ${{ matrix.build.context || '.' }}
dockerfile: ${{ matrix.build.dockerfile }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
registry: git.devthefuture.org
registry-username: "org-bot-${{ github.repository_owner }}"
registry-password: ${{ secrets.M8A_ORG_BOT_PACKAGE_TOKEN }}
deploy:
needs: [build]
runs-on: ubuntu-latest
container:
image: devthefuture/act-runner:latest@sha256:f326ce2f586d4f55757b87d3de7baf29715ef6cbc5af7bdf6313bcf7a90e7b3d
steps:
- name: 🎡 Check out the Helm chart repository
uses: actions/checkout@v4
with:
repository: "${{ github.repository_owner }}/appsets"
token: ${{ secrets.M8A_ORG_BOT_REPO_TOKEN }}
ref: "main"
- name: 🚀 Upgrade images tag
uses: https://git.devthefuture.org/devthefuture/actions/uptag@v0.2.3
with:
app: |
---
name: hasura
key: graphql-engine.image.tag
---
name: api
key: modjo-microservice.image.tag
---
name: files
key: modjo-microservice.image.tag
---
name: tasks
key: modjo-microservice.image.tag
---
name: watchers
key: modjo-microservice.image.tag
---
name: app
key: nginx.image.tag
---
env: ${{ startsWith(github.ref, 'refs/tags/') && 'production' || 'staging' }}
meta-tags: ${{ needs.build.outputs.tags }}
commit: "true"
push: "true"

113
.gitignore vendored
View file

@ -1,25 +1,66 @@
node_modules # OSX
.vscode/notes.txt #
yarn-error.log
*.logs
.DS_Store .DS_Store
.env.local
.env.yaml
.eslintcache
.devbox/ # Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# project.xcworkspace
ios/AlerteSecours.xcodeproj/project.xcworkspace/**
!ios/AlerteSecours.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
# bunlde sourcemaps
ios/*.map
ios/*.hbc
.archive # Android/IntelliJ
/.osm-files #
/osm-files build/
/tileserver-files .idea
.gradle
local.properties
*.iml
*.hprof
.cxx/
*.keystore
!debug.keystore
googleServiceAccountKey.json # node.js
#
node_modules/
npm-debug.log
yarn-error.log
services/*/build # Bundle artifacts
services/*/dist *.jsbundle
# CocoaPods
/ios/Pods/
# Temporary files created by Metro to check the health of the file watcher
.metro-health-check*
# Expo
.expo/
web-build/
dist/
# Yarn berry
.pnp.*
.yarn/* .yarn/*
!.yarn/patches !.yarn/patches
!.yarn/plugins !.yarn/plugins
@ -28,6 +69,46 @@ services/*/dist
!.yarn/versions !.yarn/versions
# !.yarn/cache # !.yarn/cache
# secrets
/keys
/.env.local
/.env.prod
/.env.staging
## Build generated
build/
DerivedData
/**/*.xcarchive/**
# aidigest
codebase.md codebase.md
/bin # Build logs
logs/
# Sensitive configuration files
ios/GoogleService-Info.plist
ios/AlerteSecours/GoogleService-Info.plist
ios/AlerteSecours/Supporting/Expo.plist
android/app/google-services.json
# Keep example files
!ios/GoogleService-Info.example.plist
!ios/AlerteSecours/GoogleService-Info.example.plist
!ios/AlerteSecours/Supporting/Expo.example.plist
!android/app/google-services.example.json
screenshot-*.png
/.data
# Geodae preprocessing
scripts/dae/node_modules/
scripts/dae/.yarn/*
!scripts/dae/.yarn/patches
!scripts/dae/.yarn/plugins
!scripts/dae/.yarn/releases
!scripts/dae/.yarn/sdks
!scripts/dae/.yarn/versions
src/assets/db/*.db

View file

@ -1,7 +0,0 @@
#!/bin/sh
. "$(dirname $0)/_/husky.sh"
export PATH=$PATH:$HOME/.yarn/bin
yarn commitlint --edit $1

View file

@ -1,6 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
export PATH=$PATH:$HOME/.yarn/bin
yarn lint-staged

View file

@ -1,9 +0,0 @@
**/node_modules/**
**/.git/**
**/.cache/**
**/.dev-secrets/**
**/android/**
**/ios/**
**/*.log
osm-files/**
tileserver-files/**

View file

@ -1,68 +0,0 @@
{
"bumpFiles": [
{
"filename": "package.json",
"type": "json"
},
{
"filename": "alerte-secours/package.json",
"type": "json"
},
{
"filename": "services/api/package.json",
"type": "json"
},
{
"filename": "services/tasks/package.json",
"type": "json"
},
{
"filename": "services/watchers/package.json",
"type": "json"
},
{
"filename": "services/web/package.json",
"type": "json"
},
{
"filename": "services/hasura/version.json",
"type": "json"
}
],
"types": [
{
"type": "feat",
"section": "Features"
},
{
"type": "fix",
"section": "Bug Fixes"
},
{
"type": "chore",
"hidden": true
},
{
"type": "docs",
"hidden": true
},
{
"type": "style",
"hidden": true
},
{
"type": "refactor",
"hidden": true
},
{
"type": "perf",
"hidden": true
},
{
"type": "test",
"hidden": true
}
],
"commitUrlFormat": "https://github.com/mokkapps/changelog-generator-demo/commits/{{hash}}",
"compareUrlFormat": "https://github.com/mokkapps/changelog-generator-demo/compare/{{previousTag}}...{{currentTag}}"
}

View file

@ -1,5 +0,0 @@
{
"recommendations": [
"dbaeumer.vscode-eslint"
]
}

27
.vscode/settings.json vendored
View file

@ -1,25 +1,6 @@
{ {
"path-autocomplete.pathMappings": { "i18n-ally.localesPaths": [
"~": "${folder}/src" "src/i18n",
}, "src/i18n/locales"
"editor.codeActionsOnSave": { ]
"source.fixAll.eslint": "explicit"
},
"eslint.validate": [
"javascript"
],
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"eslint.workingDirectories": [{ "mode": "auto" }],
"files.associations": {
".env.{default,local}": "dotenv",
"package.json.*": "json"
},
"javascript.suggest.autoImports": true,
"typescript.suggest.autoImports": true,
"editor.suggestSelection": "first",
"vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
"editor.inlineSuggest.enabled": true
} }

View file

@ -3,17 +3,14 @@
module.exports = { module.exports = {
name: "@yarnpkg/plugin-fetch", name: "@yarnpkg/plugin-fetch",
factory: function (require) { factory: function (require) {
var plugin=(()=>{var le=Object.defineProperty;var pe=(s,e,t)=>e in s?le(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var c=(s=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(s,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):s)(function(s){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+s+'" is not supported')});var i=(s,e)=>()=>(e||s((e={exports:{}}).exports,e),e.exports);var f=(s,e,t)=>(pe(s,typeof e!="symbol"?e+"":e,t),t);var $=i((Ue,A)=>{"use strict";A.exports=function(e){return e.map(function(t){return t&&typeof t=="object"?t.op.replace(/(.)/g,"\\$1"):/["\s]/.test(t)&&!/'/.test(t)?"'"+t.replace(/(['\\])/g,"\\$1")+"'":/["'\s]/.test(t)?'"'+t.replace(/(["\\$`!])/g,"\\$1")+'"':String(t).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g,"$1\\$2")}).join(" ")}});var H=i((Ve,v)=>{var C=c("fs"),ue=c("path"),{parseSyml:fe}=c("@yarnpkg/parsers"),ke=["patch","npm","portal","link"],B=s=>{let e=s.trim().split("@");return s.startsWith("@")?e=e.slice(0,2):e=e.slice(0,1),e.join("@")},Y=(s,e)=>{let[t,r]=s.trim().split(`@${e}:`);return{key:t,version:r}},de=s=>{let[,e]=s.split("::")[0].split("#");return e};v.exports=function(){let e=C.readFileSync("yarn.lock","utf8"),t=fe(e),r=Object.keys(t).filter(o=>o.includes("@workspace:")),n=r.map(o=>{let[,l]=t[o].resolution.trim().split("@workspace:");return l==="."?null:l}).filter(Boolean);r.forEach(o=>{let{dependencies:l,dependenciesMeta:u,peerDependencies:b,peerDependenciesMeta:P,resolution:D,bin:ce}=t[o],[ae,w]=D.trim().split("@workspace:"),ie=ue.join(w,"package.json"),y={name:ae,version:"0.0.0",description:"**DON'T COMMIT** Generated file for caching",private:!0,dependencies:l,peerDependencies:b,peerDependenciesMeta:P,bin:ce};if(u){let m={};Object.keys(u).forEach(d=>{m[d]=l[d],delete l[d]}),y.optionalDependencies=m}if(w==="."){n.length>0&&(y.workspaces={packages:n});let m=Object.keys(t),d=new Map;m.forEach(p=>{p.split(",").forEach(k=>{if(k.includes("builtin<compat/"))return;let a=B(k);d.has(a)||d.set(a,[]),d.get(a).push(k)})}),y.resolutions=m.filter(p=>{var a;if(p.includes("@workspace:"))return!1;if(p.includes("@patch:"))return!((a=de(Y(p,"patch").version).match(/(\.\.\/)+/))!=null&&a.length);if(p.includes(", "))return!1;let k=B(p);return d.get(k).length===1}).reduce((p,k)=>(ke.forEach(a=>{if(!k.includes(`@${a}:`))return;let{key:x,version:g}=Y(k,a);switch(a){case"npm":p[x]=g.includes("@")?`${a}:${g}`:g;break;case"patch":k.includes("builtin<compat/")||(p[x]=`${a}:${g.split("::")[0]}`);break;case"portal":case"link":p[x]=`${a}:${g.split("::")[0]}`;break}}),p),{})}C.mkdirSync(w,{recursive:!0}),C.writeFileSync(ie,`${JSON.stringify(y,null,2)} var plugin=(()=>{var M=Object.defineProperty;var R=(n,t,e)=>t in n?M(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var o=(n=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(n,{get:(t,e)=>(typeof require<"u"?require:t)[e]}):n)(function(n){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+n+'" is not supported')});var f=(n,t)=>()=>(t||n((t={exports:{}}).exports,t),t.exports);var g=(n,t,e)=>(R(n,typeof t!="symbol"?t+"":t,e),e);var P=f((ce,F)=>{"use strict";F.exports=function(t){return t.map(function(e){return e&&typeof e=="object"?e.op.replace(/(.)/g,"\\$1"):/["\s]/.test(e)&&!/'/.test(e)?"'"+e.replace(/(['\\])/g,"\\$1")+"'":/["'\s]/.test(e)?'"'+e.replace(/(["\\$`!])/g,"\\$1")+'"':String(e).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g,"$1\\$2")}).join(" ")}});var E=f((oe,J)=>{var j=o("fs"),z=o("path"),{parseSyml:G}=o("@yarnpkg/parsers");J.exports=function(){let t=j.readFileSync("yarn.lock","utf8"),e=G(t),d=Object.keys(e).filter(i=>i.includes("@workspace:")),s=d.map(i=>{let[,p]=e[i].resolution.trim().split("@workspace:");return p==="."?null:p}).filter(Boolean);d.forEach(i=>{let{dependencies:p,dependenciesMeta:r,peerDependencies:q,peerDependenciesMeta:w,resolution:C,bin:Y}=e[i],[B,b]=C.trim().split("@workspace:"),H=z.join(b,"package.json"),h={name:B,version:"0.0.0",description:"**DON'T COMMIT** Generated file for caching",private:!0,dependencies:p,peerDependencies:q,peerDependenciesMeta:w,bin:Y};if(r){let m={};Object.keys(r).forEach(k=>{m[k]=p[k],delete p[k]}),h.optionalDependencies=m}if(b==="."){s.length>0&&(h.workspaces={packages:s});let m=Object.keys(e),k=c=>{let a=c.trim().split("@");return c.startsWith("@")?a=a.slice(0,2):a=a.slice(0,1),a.join("@")};h.resolutions=m.filter(c=>{if(c.includes("@workspace:")||c.includes(", ")||!c.includes("@npm:"))return!1;let a=k(c);return m.every(y=>c===y?!0:y.split(",").map(l=>k(l)).every(l=>l!==a))}).reduce((c,a)=>{let[y,l]=a.trim().split("@npm:");return c[y]=l.includes("@")?`npm:${l}`:l,c},{})}j.mkdirSync(b,{recursive:!0}),j.writeFileSync(H,`${JSON.stringify(h,null,2)}
`)})}});var j=i((Ze,R)=>{var he=H();R.exports=s=>{s.context.stdout.write(`[YARN-FETCH] extracting package.json file(s) from yarn.lock `)})}});var S=f((ae,T)=>{var I=E();T.exports=n=>{n.context.stdout.write(`[YARN-FETCH] extracting package.json file(s) from yarn.lock
`),he()}});var K=i((Xe,L)=>{var h=c("fs"),me=c("path"),{execSync:ge}=c("child_process"),{parseSyml:ye}=c("@yarnpkg/parsers"),{BaseCommand:xe}=c("@yarnpkg/cli"),{Command:qe,Option:M}=c("clipanion"),be=$(),Pe=j(),q;L.exports=(q=class extends xe{protectPackageJson=M.Boolean("--protect-package-json");args=M.Proxy();async execute(){let{protectPackageJson:e=process.stdout.isTTY}=this,t=[];if(e){this.context.stdout.write(`[YARN-FETCH] backup possible package.json file(s) `),I()}});var O=f((pe,N)=>{var u=o("fs"),K=o("path"),{execSync:U}=o("child_process"),{parseSyml:W}=o("@yarnpkg/parsers"),{BaseCommand:Z}=o("@yarnpkg/cli"),{Command:Q,Option:D}=o("clipanion"),V=P(),X=S(),x;N.exports=(x=class extends Z{protectPackageJson=D.Boolean("--protect-package-json");args=D.Proxy();async execute(){let{protectPackageJson:t=process.stdout.isTTY}=this,e=[];if(t){this.context.stdout.write(`[YARN-FETCH] backup possible package.json file(s)
`);let n=h.readFileSync("yarn.lock","utf8"),o=ye(n);t=Object.keys(o).filter(u=>u.includes("@workspace:")).map(u=>{let{resolution:b}=o[u],[,P]=b.trim().split("@workspace:");return me.join(P,"package.json")}),t.forEach(u=>{h.existsSync(u)&&!h.existsSync(`${u}.yarn-plugin-fetch-bak`)&&h.copyFileSync(u,`${u}.yarn-plugin-fetch-bak`)})}Pe(this);let r=`yarn ${be(this.args)}`;this.context.stdout.write(`[YARN-FETCH] ${r} `);let s=u.readFileSync("yarn.lock","utf8"),i=W(s);e=Object.keys(i).filter(r=>r.includes("@workspace:")).map(r=>{let{resolution:q}=i[r],[,w]=q.trim().split("@workspace:");return K.join(w,"package.json")}),e.forEach(r=>{u.existsSync(r)&&!u.existsSync(`${r}.yarn-plugin-fetch-bak`)&&u.copyFileSync(r,`${r}.yarn-plugin-fetch-bak`)})}X(this);let d=`yarn ${V(this.args)}`;this.context.stdout.write(`[YARN-FETCH] ${d}
`);try{ge(r,{stdio:"inherit"})}catch(n){throw n}finally{e&&(this.context.stdout.write(`[YARN-FETCH] restoring possible package.json file(s) `);try{U(d,{stdio:"inherit"})}catch(s){throw s}finally{t&&(this.context.stdout.write(`[YARN-FETCH] restoring possible package.json file(s)
`),t.forEach(n=>{h.existsSync(`${n}.yarn-plugin-fetch-bak`)?h.renameSync(`${n}.yarn-plugin-fetch-bak`,n):h.unlinkSync(n)}))}}},f(q,"paths",[["fetch"]]),f(q,"usage",qe.Usage({description:"fetch dependencies from yarn.lock in Docker build",details:` `),e.forEach(s=>{u.existsSync(`${s}.yarn-plugin-fetch-bak`)?u.renameSync(`${s}.yarn-plugin-fetch-bak`,s):u.unlinkSync(s)}))}}},g(x,"paths",[["fetch"]]),g(x,"usage",Q.Usage({description:"fetch dependencies from yarn.lock in Docker build",details:`
expand yarn.lock to package.json file(s) and install dependencies in Docker build. expand yarn.lock to package.json file(s) and install dependencies in Docker build.
`,examples:[["yarn fetch --immutable","yarn fetch workspace my-package focus"]]})),q)});var W=i((st,I)=>{var{BaseCommand:we}=c("@yarnpkg/cli"),$e=j(),S;I.exports=(S=class extends we{async execute(){$e(this)}},f(S,"paths",[["fetch-tools","expand-lock"]]),S)});var z=i((rt,_)=>{function Ce(s,e,t){let r=e.split("."),n=s;for(let o of r){if(n[o]===void 0)return t;n=n[o]}return n}function je(s,e,t){let r=e.split("."),n=s;for(let o=0;o<r.length-1;o++){let l=r[o];(!n[l]||typeof n[l]!="object")&&(n[l]={}),n=n[l]}return n[r[r.length-1]]=t,s}function Se(s,e){let t=e.split("."),r=s;for(let n=0;n<t.length-1;n++){let o=t[n];if(!r[o])return!1;r=r[o]}return delete r[t[t.length-1]],!0}_.exports={get:Ce,set:je,unset:Se}});var E=i((ot,U)=>{var G=c("fs"),{get:Ee,set:Fe,unset:Je}=z();U.exports=function(e,t){let r=JSON.parse(G.readFileSync("package.json","utf-8")),n=Ee(r,e);n!==void 0&&(Fe(r,t,n),Je(r,e),G.writeFileSync("package.json",JSON.stringify(r,null,2)))}});var F=i((ct,V)=>{var Ne=E();V.exports=function(){Ne("scripts._postinstall","scripts.postinstall")}});var Q=i((it,Z)=>{var{BaseCommand:Te}=c("@yarnpkg/cli"),Oe=F(),J;Z.exports=(J=class extends Te{async execute(){Oe()}},f(J,"paths",[["fetch-tools","disable-postinstall"]]),J)});var N=i((pt,X)=>{var De=E();X.exports=function(){De("scripts.postinstall","scripts._postinstall")}});var te=i((ft,ee)=>{var{BaseCommand:Ae}=c("@yarnpkg/cli"),Be=N(),T;ee.exports=(T=class extends Ae{async execute(){Be()}},f(T,"paths",[["fetch-tools","disable-postinstall"]]),T)});var re=i((ht,ne)=>{var{execSync:Ye}=c("child_process"),{BaseCommand:ve}=c("@yarnpkg/cli"),{Option:se}=c("clipanion"),He=$(),Re=F(),Me=N(),O;ne.exports=(O=class extends ve{postinstall=se.Boolean("--postinstall");args=se.Proxy();async execute(){this.postinstall||(this.context.stdout.write(`[YARN-FETCH] disable postinstall command in package.json `,examples:[["yarn fetch --immutable","yarn fetch workspace my-package focus"]]})),x)});var A=f((ke,v)=>{var{BaseCommand:_}=o("@yarnpkg/cli"),ee=S(),$;v.exports=($=class extends _{async execute(){ee(this)}},g($,"paths",[["expand-lock"]]),$)});var se=f((de,L)=>{var te=O(),ne=A();L.exports={commands:[te,ne]}});return se();})();
`),Me());let e=`yarn workspaces focus --production ${He(this.args)}`;this.context.stdout.write(`[YARN-FETCH] ${e}
`),Ye(e,{stdio:"inherit"}),this.postinstall||(this.context.stdout.write(`[YARN-FETCH] re-enable postinstall command in package.json
`),Re())}},f(O,"paths",[["fetch-tools","production"]]),O)});var ze=i((gt,oe)=>{var Le=K(),Ke=W(),Ie=Q(),We=te(),_e=re();oe.exports={commands:[Le,Ke,We,Ie,_e]}});return ze();})();
return plugin; return plugin;
} }
}; };

File diff suppressed because one or more lines are too long

View file

@ -5,8 +5,7 @@ enableGlobalCache: false
nodeLinker: node-modules nodeLinker: node-modules
plugins: plugins:
- checksum: 240d225dd5bf1e25068497140ced7a3b7658a4c3754c08ea57162c9fe3335d757af0eae55555f96150a3015cdd0337852401f3fae69c1edd05221cb32f038d8c - path: .yarn/plugins/@yarnpkg/plugin-fetch.cjs
path: .yarn/plugins/@yarnpkg/plugin-fetch.cjs spec: "https://raw.githubusercontent.com/devthejo/yarn-plugin-fetch/master/bundles/@yarnpkg/plugin-fetch.js"
spec: "https://codeberg.org/devthefuture/yarn-plugin-fetch/raw/branch/master/bundles/@yarnpkg/plugin-fetch.js"
yarnPath: .yarn/releases/yarn-4.10.3.cjs yarnPath: .yarn/releases/yarn-4.5.3.cjs

View file

@ -1,191 +1,266 @@
# Alerte-Secours Services - Developer Documentation # Alerte Secours Mobile App - Developer Documentation
This document contains technical information for developers working on the Alerte-Secours microservices backend. This document contains technical information for developers working on the Alerte Secours mobile application.
## Development Quick Start ## Table of Contents
### Requirements - [Project Overview](#project-overview)
- [Technical Stack](#technical-stack)
- [Development Quick Start](#development-quick-start)
- [Installation](#installation)
- [Android](#android)
- [iOS](#ios)
- [Project Structure](#project-structure)
- [Accessibility](#accessibility)
- [Troubleshooting](#troubleshooting)
- Docker ## Project Overview
- Devbox
- Android SDK (for mobile development)
- Java 8+ (for Android development)
### Installation Alerte Secours is a mobile application built with React Native that handles alerts and emergency-related functionality. The app supports both iOS and Android platforms and includes features such as:
1. Clone the repository: - Alert creation and management with real-time updates
```sh - Location-based features with mapping integration
git clone https://codeberg.org/alerte-secours/alerte-secours - Chat/Messaging system with alert-specific chat rooms
cd alerte-secours - Authentication via SMS verification
``` - Deep linking for alert sharing
- Push notifications
2. Install devbox if not already installed:
```sh
curl -fsSL https://get.jetpack.io/devbox | bash
```
3. Enter devbox shell (this will automatically install Node.js 20 and Yarn 4.6.0):
```sh
devbox shell
```
4. Install dependencies:
```sh
yarn
```
5. Set up environment variables:
```sh
cp .env.default .env
```
### Start Services
Start all services with Tilt:
```sh
yarn dev
# or
devbox run dev
# or run a subset of services:
tilt up api files hasura
```
View logs in Tilt UI (web HUD opens automatically). CLI alternative:
```sh
yarn dev:logs
# or
tilt logs
```
Stop services:
```sh
# If running in the foreground terminal:
Ctrl-C
# Or explicitly:
tilt down
```
Compose fallback (legacy):
```sh
yarn compose:up
yarn compose:down
# or via devbox:
devbox run compose:up
devbox run compose:down
```
### Using Devbox
Once you're in the devbox shell, you have access to:
- Node.js 20 (automatically installed)
- Yarn 4.6.0 (automatically installed)
- All project scripts and environment variables
- PostgreSQL client tools
To exit the devbox shell:
```sh
exit
```
To run commands from outside the shell:
```sh
devbox run <command>
```
Available devbox scripts:
- `devbox run dev` - Start development environment
- `devbox run dev:up` - Start all services
- `devbox run dev:logs` - View development logs
- `devbox run console` - Open development console
### Public Staging Environment
For development and testing, you can use our public staging environment:
- API: https://api-staging.alerte-secours.fr
- GraphQL: https://graphql-staging.alerte-secours.fr
- Web Interface: https://web-staging.alerte-secours.fr
### Endpoints (Local Development)
#### Services
- API: http://localhost:4200
- Files: http://localhost:4292
- Hasura: http://localhost:4201
- Tasks Service
- Watchers Service
- Web: http://localhost:4203
#### Consoles
- [Hasura Console](http://localhost:4295)
- [Minio Console](http://localhost:4291)
- [API Swagger](http://localhost:4200/api/v1/swagger/)
- [API GraphQL](http://localhost:4200/api/v1/graphql)
- [Files API](http://localhost:4292/api/v1/swagger/)
#### API URLs
- `/api/v1`
- `/spec` - API Specification
- `/oas` - OpenAPI Service
- `/swagger` - Swagger Documentation
- `/graphql` - GraphQL Endpoint
- `/status` - Service Status
- `/` - Root Endpoint
## Technical Stack ## Technical Stack
### Backend - React Native
- **Node.js** (>=20) - Core runtime - Expo framework
- **PostgreSQL** - Primary database - GraphQL with Hasura
- **Redis** - Caching and queue deduplication - Apollo Client for frontend
- **RabbitMQ** - Message queue - Federated remote schemas
- **Hasura** - GraphQL engine - Real-time subscriptions support
- **OpenAPI** - API specification and documentation - Firebase Cloud Messaging (FCM) for push notifications only
- **Modjo Framework** - Microservices architecture - Sentry for error tracking
- MapLibre for mapping functionality
- Zustand for state management
- i18next for internationalization
- React Navigation for navigation
- Expo Updates for OTA updates
- Background Geolocation for location tracking
- Lottie for animations
- React Hook Form for form handling
- Axios for HTTP requests
- Yarn Berry as package manager
- ESLint and Prettier for code quality
- Fastlane for deployment automation
### Frontend ## Development Quick Start
- **React** - Web interface
- **React Native** - Mobile application
- **Apollo Client** - GraphQL integration
- **MapView** - Geolocation visualization
### Infrastructure ### Prerequisites
- **Docker** - Containerization
- **Microservices Architecture** - Separate services for API, files, tasks, etc.
- **CQRS Pattern** - Command Query Responsibility Segregation
- **Event-Driven Architecture** - Using message queues
### Key Features - Node.js (version specified in `.node-version`)
- Real-time alerts and notifications - Yarn package manager
- Geolocation tracking and mapping - Android Studio (for Android development)
- Emergency services integration - Xcode (for iOS development)
- User authentication and authorization - Physical device or emulator/simulator
- File storage and management
- Background task processing ### Environment Setup
1. Clone the repository
2. Install dependencies:
```bash
yarn
```
3. Copy the staging environment file:
```bash
cp .env.staging.example .env.staging
```
4. Start the development server with staging environment:
```bash
yarn start:staging
```
### Running on Devices
#### Android
```bash
yarn android:staging
```
#### iOS
```bash
yarn ios:staging
```
### Staging URLs
The staging environment uses the following URLs:
- GraphQL API: `https://hasura-staging.alertesecours.fr/v1/graphql`
- WebSocket: `wss://hasura-staging.alertesecours.fr/v1/graphql`
- Files API: `https://files-staging.alertesecours.fr/api/v1/oas`
- Minio: `https://minio-staging.alertesecours.fr`
- Geolocation Sync: `https://api-staging.alertesecours.fr/api/v1/oas/geoloc/sync`
## Installation
### Android
#### Using the Yarn Script
The easiest way to install the app is to use the provided yarn script:
```bash
# Set the device ID (emulator or physical device)
export DEVICE=emulator-5554
# Run the installation script
yarn install:android
```
This script (`install-android.sh`) handles the entire installation process, including building APKs with signing, extracting them, and installing on the device.
#### Manual Installation
If you need to install the app manually, you can examine the `install-android.sh` script in the project root to see the detailed steps involved.
### iOS
#### Authentication Key Setup
1. Go to https://appstoreconnect.apple.com/access/integrations/api
2. Click the "+" button to generate a new API key
3. Give it a name (e.g., "AlerteSecours Build Key")
4. Download the .p8 file when prompted
5. Store the .p8 file in a secure location
6. Note down the Key ID and Issuer ID shown on the website
7. Set up environment variables:
```sh
export ASC_API_KEY_ID="YOUR_KEY_ID"
export ASC_API_ISSUER_ID="YOUR_ISSUER_ID"
export ASC_API_KEY_PATH="/path/to/your/AuthKey.p8"
```
#### Building and Running
To build and run the iOS app:
```bash
# Run in development mode with staging environment
yarn ios:staging
# Build for production (version + clean + archive + export)
yarn bundle:ios:build
# Upload the last build to App Store Connect
yarn bundle:ios:upload
# Build + upload
yarn bundle:ios:release
```
Notes on versioning:
- `yarn bundle:ios:build` updates iOS `CFBundleShortVersionString` and `CFBundleVersion` to a timestamp in `Europe/Paris` timezone (format `YYYYMMDDHHMM`) before archiving/exporting.
- `yarn bundle:ios` is an alias of `yarn bundle:ios:build`.
The `bundle:ios` command uses the scripts in the `scripts` directory:
- `ios-archive.sh` - Archives the iOS app
- `ios-export.sh` - Exports the archived app
- `ios-upload.sh` - Uploads the app to App Store Connect (used by `bundle:ios:upload`)
## Project Structure ## Project Structure
``` - `/android` - Android-specific code and configuration
services/ - `/ios` - iOS-specific code and configuration
├── api/ # Main API service - `/src` - Main application source code
├── app/ # Frontend application - `/app` - App initialization and configuration
├── files/ # File handling service - `/assets` - Static assets (images, fonts, animations)
├── hasura/ # GraphQL engine - `/auth` - Authentication-related code
├── tasks/ # Background task processing - `/biz` - Business logic and constants
├── watchers/ # Event monitoring - `/components` - Reusable UI components
└── web/ # Web interface - `/containers` - Container components
- `/data` - Data management
libs/ - `/events` - Event handling
├── common/ # Shared utilities - `/finders` - Search and finder utilities
├── postgres-types/ # Database type definitions - `/gql` - GraphQL queries and mutations
├── redis-queue-dedup/ # Redis queue deduplication - `/hoc` - Higher-order components
└── utils/ # General utilities - `/hooks` - Custom React hooks
``` - `/i18n` - Internationalization
- `/layout` - Layout components
- `/lib` - Library code
- `/location` - Location-related functionality
- `/misc` - Miscellaneous utilities
- `/navigation` - Navigation configuration
- `/network` - Network-related code
- `/notifications` - Notification handling
- `/permissions` - Permission handling
- `/scenes` - Scene components
- `/screens` - Screen components
- `/sentry` - Sentry error tracking configuration
- `/stores` - State management stores
- `/theme` - Styling and theming
- `/updates` - Update handling
- `/utils` - Utility functions
- `/docs` - Documentation files
- `/scripts` - Utility scripts for building, deployment, and development
- `/e2e` - End-to-end tests
## Contributing ## Contributing
We welcome contributions to Alerte-Secours. Please read our contribution guidelines before submitting pull requests. Guidelines for contributing to the project:
## Support 1. Follow the code style and conventions used in the project
2. Write tests for new features
3. Update documentation as needed
4. Use the ESLint and Prettier configurations
For technical support, please open an issue on our [Codeberg issue tracker](https://codeberg.org/alerte-secours/alerte-secours/-/issues) or [GitHub issue tracker](https://github.com/alerte-secours/alerte-secours/issues). ## Accessibility
This app has an accessibility baseline (WCAG 2.2 AA, VoiceOver/TalkBack) and app-specific conventions.
### Docs
- Baseline checklist: [`docs/a11y-wcag22-aa.md`](docs/a11y-wcag22-aa.md:1)
- Code conventions + helpers: [`docs/a11y-usage.md`](docs/a11y-usage.md:1)
- Color contrast guidance: [`docs/a11y-color-contrast.md`](docs/a11y-color-contrast.md:1)
- `testID` conventions: [`docs/testids.md`](docs/testids.md:1)
- QA runbook (iOS VoiceOver): [`docs/qa-voiceover.md`](docs/qa-voiceover.md:1)
- QA runbook (Android TalkBack): [`docs/qa-talkback.md`](docs/qa-talkback.md:1)
### PR checklist (required for any UI change)
- [ ] **Roles / labels / hints / states**: all interactive controls expose correct `accessibilityRole`, meaningful `accessibilityLabel`, helpful `accessibilityHint` (especially icon-only actions), and state where applicable.
- [ ] **Focus management**: any modal/dialog/sheet sets initial focus on open, returns focus on close, and avoids focus traps.
- [ ] **Touch target size**: critical tap targets are comfortably tappable (aim ~44x44pt minimum).
- [ ] **Color contrast**: text + icons meet WCAG AA contrast; do not rely on color alone for meaning.
- [ ] **`testID`s for critical controls**: stable `testID` added/updated for key actions and navigation chrome (per [`docs/testids.md`](docs/testids.md:1)).
- [ ] **Tests**: add/update tests covering the new UI behavior (and its states). Prefer assertions that dont depend on translated text; include E2E coverage for critical flows when applicable.
### Manual validation (screen readers)
When a PR changes UI or navigation, do a quick pass with the platform screen reader:
- iOS: follow [`docs/qa-voiceover.md`](docs/qa-voiceover.md:1) and validate labels/hints, navigation order, and activation behavior on the affected screens.
- Android: follow [`docs/qa-talkback.md`](docs/qa-talkback.md:1) with the same focus on discoverability, focus order, and activation.
## Troubleshooting
### Common Issues
#### Development Environment
- **Clearing Yarn Cache**: Use `yarn clean` (removes node_modules and reinstalls dependencies)
- **Cleaning Gradle**: Run `cd android && ./gradlew clean`
- **Clearing Gradle Cache**: Remove gradle caches with `rm -rf ~/.gradle/caches/ android/.gradle/`
- **Stopping Gradle Daemons**: Run `cd android && ./gradlew --stop`
- **Clearing ADB Cache**: Run `adb shell pm clear com.alertesecours`
- **Rebuilding Gradle**: Use `yarn expo run:android`
- **Rebuilding Expo React Native**: Use `yarn expo prebuild`
- **Clearing Metro Cache**: Use `yarn expo start --dev-client --clear`
#### Screenshots and Testing
- For Android screenshots: Use `scripts/screenshot-android.sh`
- For iOS screenshots: Use `scripts/screenshot-ios.sh`
- For Android emulator: Use `scripts/android-emulator`
#### Emulator Issues
- Clear cache / uninstall the app
- Check emulator datetime
- Check network connectivity
For more troubleshooting tips, see the documentation in the `/docs` directory.

View file

@ -1,38 +1,57 @@
# Alerte-Secours - Le Réflexe qui Sauve # Alerte Secours - Le Réflexe qui Sauve
[![Liberapay](https://img.shields.io/liberapay/receives/alerte-secours.svg?logo=liberapay)](https://liberapay.com/alerte-secours) [![Liberapay](https://img.shields.io/liberapay/receives/alerte-secours.svg?logo=liberapay)](https://liberapay.com/alerte-secours)
[![Buy Me a Coffee](https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg?logo=buy-me-a-coffee)](https://buymeacoffee.com/alertesecours) [![Buy Me a Coffee](https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg?logo=buy-me-a-coffee)](https://buymeacoffee.com/alertesecours)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/alerte-secours?style=social)](https://github.com/sponsors/alerte-secours) [![GitHub Sponsors](https://img.shields.io/github/sponsors/alerte-secours?style=social)](https://github.com/sponsors/alerte-secours)
Alerte-Secours est un système d'alerte et de réponse d'urgence basé sur une architecture de microservices, conçu pour fournir une assistance rapide en situation d'urgence. Une application mobile pour la gestion des alertes et des fonctionnalités liées aux urgences, supportant les plateformes iOS et Android.
## Site Web Officiel **Site Web Officiel :** [alerte-secours.fr](https://alerte-secours.fr)
Visitez notre site web officiel sur [alerte-secours.fr](https://alerte-secours.fr) ## Aperçu du Projet
Alerte Secours est une application mobile construite avec React Native qui gère les alertes et les fonctionnalités liées aux urgences. L'application supporte les plateformes iOS et Android et inclut des fonctionnalités telles que :
- Création et gestion d'alertes avec mises à jour en temps réel
- Fonctionnalités basées sur la localisation avec intégration cartographique
- Système de chat/messagerie avec salles de discussion spécifiques aux alertes
- Authentification via vérification SMS
- Liens profonds pour le partage d'alertes
- Notifications push
## Documentation Développeur ## Documentation Développeur
Pour les développeurs souhaitant contribuer au projet ou déployer les services, consultez la [documentation technique complète](DEVELOPER.md) qui contient : Pour les développeurs souhaitant contribuer au projet ou déployer l'application, consultez la [documentation technique complète](DEVELOPER.md) qui contient :
- Guide de démarrage rapide - Aperçu du projet et fonctionnalités
- Stack technique détaillé - Stack technique détaillé
- Instructions d'installation - Guide de démarrage rapide
- Documentation des API - Instructions d'installation (Android/iOS)
- Structure du projet - Structure du projet
- Endpoints de développement - Guide de dépannage
- Instructions de build et déploiement
## Licence ## Licence
Alerte-Secours est sous licence **DevTheFuture Ethical Use License (DEF License)**. Alerte Secours est sous licence **DevTheFuture Ethical Use License (DEF License)**. Points clés :
Points clés : ### Usage à but non lucratif
- **Usage à but non lucratif** : Gratuit pour les usages à but non lucratif - Licence perpétuelle, libre de redevances et non exclusive pour usage à but non lucratif
- **Usage commercial** : Nécessite une licence payante - Permet l'utilisation, la modification et la distribution à des fins non lucratives
- **Données personnelles** : Ne doivent pas être monétisées ou exploitées
- **Propriété** : Tous les droits de propriété intellectuelle restent au concédant
- **Restriction concurrentielle** : Les concurrents doivent obtenir une autorisation explicite
Pour les détails complets de la licence, voir [LICENSE.md](LICENSE.md). ### Usage commercial
- Nécessite l'obtention d'une licence payante
- Conditions déterminées par le Concédant (DevTheFuture.org)
### Restrictions sur les données personnelles
- Ne doit pas être utilisé pour monétiser, vendre ou exploiter les données personnelles
- Les données personnelles ne peuvent pas être utilisées pour le marketing, la publicité ou l'influence politique
- L'agrégation de données n'est autorisée que si c'est une fonctionnalité explicite divulguée aux utilisateurs
### Restriction concurrentielle
- Les concurrents sont interdits d'utiliser le logiciel sans consentement explicite
Pour le texte complet de la licence, voir [LICENSE.md](LICENSE.md).
## 💙 Soutenir le projet ## 💙 Soutenir le projet
@ -51,8 +70,13 @@ Si vous souhaitez contribuer à son développement, sa maintenance et son indép
## Contribuer ## Contribuer
Nous accueillons les contributions à Alerte-Secours. Veuillez lire nos directives de contribution avant de soumettre des pull requests. Directives pour contribuer au projet :
1. Suivez le style de code et les conventions utilisées dans le projet
2. Écrivez des tests pour les nouvelles fonctionnalités
3. Mettez à jour la documentation si nécessaire
4. Utilisez les configurations ESLint et Prettier
## Support ## Support
Pour obtenir de l'aide, veuillez ouvrir un ticket sur notre [tracker d'issues Codeberg](https://codeberg.org/alerte-secours/alerte-secours/-/issues) ou [tracker d'issues GitHub](https://github.com/alerte-secours/alerte-secours/issues). Pour obtenir de l'aide, veuillez ouvrir un ticket sur notre tracker d'issues ou consulter la documentation dans le répertoire `/docs`.

View file

@ -1,38 +0,0 @@
# Tiltfile for as-services
# Orchestrates docker-compose services with Tilt, providing a unified UI/logs and incremental workflows.
# Watch ignores are configured via .tiltignore
# Ensure .env exists so docker-compose gets expected env
local_resource(
name="ensure-env",
cmd="bash -lc 'if [ ! -f .env ] && [ -f .env.default ]; then cp .env.default .env && echo Created .env from .env.default; fi'",
allow_parallel=True,
auto_init=True,
)
# Optional: pre-pull builder image used in Dockerfiles
local_resource(
name="pull-builder",
cmd="docker pull devthefuture/dockerfile-x",
allow_parallel=True,
auto_init=True,
)
# Drive docker-compose with Tilt
dc = docker_compose('./docker-compose.yaml')
# Compose services are registered via docker_compose; explicit resource dependencies
# removed for compatibility with Tilt v0.35 (resource_deps not available).
# Optional groups for readability (requires Tilt Teams; keep commented if not used)
# set_team_ui_settings({
# 'resource_groups': {
# 'core': ['db', 'rabbitmq', 'redis-q-dedup', 'redis-hot-geodata', 'kvrocks-cold-geodata', 'maildev'],
# 'object-storage': ['minio', 'minio-setup'],
# 'hasura': ['hasura', 'hasura_console'],
# 'api-stack': ['api', 'files', 'tasks', 'watchers'],
# 'geo': ['osrm-car', 'osrm-foot', 'tileserver-gl', 'nominatim', 'nominatim-pg'],
# 'frontends': ['web', 'app'],
# }
# })

View file

Before

Width:  |  Height:  |  Size: 692 B

After

Width:  |  Height:  |  Size: 692 B

View file

Before

Width:  |  Height:  |  Size: 903 B

After

Width:  |  Height:  |  Size: 903 B

View file

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 160 KiB

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 426 B

View file

Before

Width:  |  Height:  |  Size: 571 B

After

Width:  |  Height:  |  Size: 571 B

View file

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 160 KiB

View file

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View file

Before

Width:  |  Height:  |  Size: 985 B

After

Width:  |  Height:  |  Size: 985 B

View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 160 KiB

View file

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 160 KiB

View file

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 160 KiB

View file

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View file

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View file

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

View file

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View file

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Some files were not shown because too many files have changed in this diff Show more