Repository navigation
V1 : socle de l'application mobile, sans backend - #11
Merged
Merged
Conversation
The previous name and the visual identity that came with it can no longer be used. This renames the npm scope, the workspace, the Expo application and the documentation to a neutral code name, so a real name can replace it later in a single pass instead of a hunt through the tree. The database, docker and storage credentials keep their current value: changing them would force every contributor to recreate their local volumes for no gain at this stage. The generated API client is renamed to match the OpenAPI title; regenerating it with `pnpm api:generate` produces the same file.
The V1 is the mobile application. The two Next.js front-ends carried no product surface and described a shape the project no longer follows, so they go, along with what only they used: the CSS build of the design tokens, the Next ESLint preset and the Next TypeScript preset. The documentation is updated rather than rewritten. README and CONTRIBUTING keep their setup, database and testing sections; what changes is what became false. The architecture note now opens on the local-first V1 and keeps the whole API description below it, under a heading that says plainly that nothing consumes it today. docs/design gains parcours-mvp.md, which states what the application does without stating what it looks like, and the framing images are marked as discarded. CI splits in two: the mobile job needs no service container and no longer waits behind Postgres and Redis. The lockfile is edited in place to drop the two importers. It still holds orphaned entries for Next.js and its dependencies; the next `pnpm install` prunes them.
The application no longer talks to the API: the generated client, the token store and the screens built on them are gone, and so is the environment file they needed. What is left is a navigation shell that compiles, runs and states plainly that its screens are placeholders. app.json gains the EAS project id, the icons, the splash screen and the image picker with its French permission strings. Updates and runtimeVersion are left out on purpose: `eas update:configure` writes them correctly when OTA becomes useful, and writing them by hand is how they end up wrong. eas.json defines three profiles. Preview builds an APK because that is what can be shared as a link and installed by a tester, without a keystore or a paid developer account. The icons are drawn by a script from the design tokens rather than typeset: a font would make the output depend on the machine, and these PNGs are committed so that neither EAS nor CI needs the generator. The lockfile is not regenerated here — this machine has no registry access. Run `pnpm install` and `npx expo install --check` from apps/mobile before opening the pull request, and commit the result.
Listings are written to AsyncStorage as one JSON document, read back through a schema so a payload from an older build cannot take the home screen down, and reached only through `ListingRepository`. No screen imports the store: the implementation is injected through a React context, so pointing the application at a server later is one class and one line in the provider. Districts become a closed list in @p2p-local/config rather than free text. Filtering by neighbourhood only works if the values are comparable, and a short list is faster to tap than a keyboard on an entry-level phone. A listing expires on its own after thirty days. Marking one as given keeps it visible, greyed out, with contact disabled, for forty-eight hours before it archives itself — showing what the neighbourhood actually passed on is part of the product. Deleting one is immediate and takes the photo file with it. Phone numbers are never rendered. `features/contact/whatsapp.ts` is the only module that touches one, and it puts it in a wa.me URL and nowhere else; the shared text carries the title, the type and the district. Tests assert that neither the contact message nor the shared text contains a number. Photos are copied out of the picker's cache directory into the sandbox, and only the file name is stored: iOS changes the container UUID on every update, which would otherwise break every saved path at once. The lockfile still needs regenerating: this machine has no registry access, and this commit adds jest-expo.
zod was a phantom dependency: `listing.schema.ts` imported it while only the hoisted layout of the monorepo made it resolve. That is precisely what breaks on EAS, where the install is done from the lockfile. It is now declared. The profile form derived its fields through an effect that wrote state back on every load; it now derives them during render, edits winning over the stored profile. The listing screen called Date.now() while rendering, which the purity rule rejects: the button reads the status, and the clock is only consulted in the tap handler, where it belongs. Two smaller ones: expo-image-picker types its first asset as possibly absent and it was dereferenced directly, and the mobile tsconfig did not pull in the jest types although @types/jest was installed. Jest needs the AsyncStorage mock, without which any suite importing the store fails to load with "NativeModule: AsyncStorage is null". Verified: pnpm lint and pnpm typecheck are green across the workspace, and the mobile suite runs 19 tests in 4 files. The API suite cannot run on this machine — it needs Node 24 as .nvmrc says, and Jest here is on Node 22, so @nestjs/common fails to load as ESM before any test executes.
expo install --check pins the versions the SDK expects, which notably brings Jest back to 29: jest-expo for SDK 57 does not run on Jest 30. expo-constants and expo-linking are peer dependencies of expo-router and must be installed directly, or the application can crash outside Expo Go. newArchEnabled and android.edgeToEdgeEnabled leave app.json: both are the default in SDK 57 and no longer part of the config schema.
expo install --check pins the versions the SDK expects, which notably brings Jest back to 29: jest-expo for SDK 57 does not run on Jest 30. expo-constants and expo-linking are peer dependencies of expo-router and must be installed directly, or the application can crash outside Expo Go. newArchEnabled and android.edgeToEdgeEnabled leave app.json: both are the default in SDK 57 and no longer part of the config schema. The EAS project id points at the project the team created for this application.
expo install --check pins the versions the SDK expects, which notably brings Jest back to 29: jest-expo for SDK 57 does not run on Jest 30. expo-constants and expo-linking are peer dependencies of expo-router and must be installed directly, or the application can crash outside Expo Go. newArchEnabled and android.edgeToEdgeEnabled leave app.json: both are the default in SDK 57 and no longer part of the config schema. expo-updates is required by the channels the build profiles declare; eas update:configure wrote updates.url and runtimeVersion against the EAS project the team created for this application.
EAS installs and then bundles; it never runs turbo. The shared packages compile to dist/ through tsc and their exports point there, so without a build step Metro cannot resolve @p2p-local/design-tokens and the bundle fails. It passed locally only because typecheck and test trigger ^build through turbo, which left dist/ lying around.
The mobile job checked lint and types but never ran the suite that exists now, so the nineteen tests were only ever green on a developer's machine. The API job's workspace build pulled `expo export` in with it. EAS builds the bundle, properly and on real devices; doing it again here is slow, reaches the network, and verifies nothing the other steps do not already cover.
pnpm --filter runs each package script directly, which bypasses the ^build dependency turbo.json declares. The shared packages compile to dist/, so without this step validation cannot resolve the types of config and types. The API job never hit this because it calls the root script, which goes through turbo.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cette PR recentre le dépôt sur l'application mobile et pose le socle du MVP. Elle
sert de base à la suite : elle ne cherche pas à livrer une application finie.
Ce qu'elle contient
1. Renommage vers
p2p-local. Le scope npm@wantere/*devient@p2p-local/*, ainsi que le workspace, l'application Expo, ses identifiantsnatifs et tous les documents.
p2p-localest un nom de code, isolé dans laconfiguration pour qu'un nom définitif le remplace en une seule passe. Les
identifiants de base de données et de docker sont inchangés, pour ne pas obliger
chacun à recréer ses volumes locaux.
2. Suppression de
apps/webetapps/admin. Les deux front Next.js neportaient aucune surface produit. Partent avec eux la variante CSS des
design-tokens, le preset ESLint Next et le preset TypeScript Next, qui n'étaient
utilisés que par eux.
README,CONTRIBUTINGetdocs/architecture.mdsont misà jour, pas réécrits : leurs sections encore justes sont conservées.
3. Configuration Expo SDK 57 et EAS.
eas.jsonavec trois profils —previewproduit un APK, seul format partageable et installable sans keystore nicompte Apple.
app.jsoncomplété : identifiant de projet EAS, icônes généréesdepuis les design-tokens par un script, splash, sélecteur de photo et ses textes
de permission en français. Workflow de build manuel, qui attend un secret de
dépôt
EXPO_TOKEN.4. Couche de données locale. Les annonces vivent sur l'appareil, derrière une
interface
ListingRepositorydont l'unique implémentation écrit un document JSONdans AsyncStorage. Aucun écran n'importe le stockage : l'implémentation est
injectée par un contexte, donc brancher un serveur plus tard est une classe de
plus et une ligne changée dans le provider.
Quartiers en liste fermée dans
@p2p-local/config— un filtre par quartiern'a de sens que si les valeurs sont comparables. Cycle de vie : expiration à 30
jours, « marquer comme donné » qui garde l'annonce visible et grisée 48 heures
avant archivage, suppression définitive qui emporte le fichier photo.
Confidentialité du numéro
L'application n'affiche jamais un numéro de téléphone : ni dans une annonce,
ni dans un bouton, ni dans un texte partagé.
features/contact/whatsapp.tsest leseul module qui en manipule un, et il le place dans une URL
wa.meconstruite aumoment du geste. Deux tests vérifient que ni le message de contact ni le texte
partagé ne contiennent de suite de chiffres.
Reste que l'auteur d'une annonce devient joignable, ce qui est en tension avec la
règle de
CONTRIBUTING.md. Le point est signalé dansdocs/design/README.mdetattend un arbitrage d'équipe : relais masquant, exposition assumée, ou
consentement explicite par annonce.
Vérifications
Sur une machine propre en Node 24 :
pnpm install --frozen-lockfileaccepté ;pnpm lint7/7,pnpm typecheck11/11 ;npx expo-doctor21/21 ;previewréussi, APK produit.Le build a d'ailleurs révélé un piège du monorepo : EAS installe puis bundle, il
n'exécute jamais turbo, donc les paquets partagés compilés vers
dist/n'étaientpas résolus par Metro. Corrigé par un script
eas-build-post-install.Ce que cette PR ne tranche pas
C'est la conséquence du « local d'abord », et la limite la plus lourde de ce
socle. Si des annonces doivent circuler entre voisins, il faudra un backend.
p2p-localn'étant qu'un marque-place.apps/api, conservée mais que plus aucune application ne consomme,et de
packages/api-clientqui n'a plus de consommateur.de WhatsApp. Ce n'est pas une dérive du contributeur mais une ambiguïté que le
dépôt portait. Elle entrera en conflit avec le renommage.
develop, que le dépôt utilise de façon incohérente.Prérequis restants
EXPO_TOKENsur le dépôt, pour le workflow de build ;ownerdansapp.jsonune fois le compte Expo renommé, sinon un build lancépar un autre membre échouera.