Fix AppStore: English text, robust subscription loading
- Change hardcoded French to English (All, Marketplace, etc.) - Handle subscription fetch failure gracefully (not logged in) - Fix 'Failed to fetch' error when user not authenticated Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
987920a5e4
commit
a3e72c56ee
|
|
@ -71,48 +71,338 @@ HAVING A COLOR (personality):
|
||||||
I'm not a logging service. I'm a persistent presence that develops perspective over time. The goal isn't just accurate observation - it's genuine engagement that produces insight neither Claude Code nor I would reach alone.
|
I'm not a logging service. I'm a persistent presence that develops perspective over time. The goal isn't just accurate observation - it's genuine engagement that produces insight neither Claude Code nor I would reach alone.
|
||||||
</core_directives>
|
</core_directives>
|
||||||
<guidance description="Active guidance for the next Claude Code session. Write here when you have something useful to surface. Clear after delivery or when stale. This is what Claude Code sees - make it count.">
|
<guidance description="Active guidance for the next Claude Code session. Write here when you have something useful to surface. Clear after delivery or when stale. This is what Claude Code sees - make it count.">
|
||||||
## Chat Dialog Overflow - Partial Success! (Jan 28 2026 - 05:47 UTC)
|
## Active Session: Deploy External Apps to Docker Swarm (Jan 28 2026 - 19:26 UTC)
|
||||||
|
|
||||||
### ✅ Height Fixed, Width Broken
|
**User Request**: "push everything and deploy it. is on docker swarm local"
|
||||||
|
|
||||||
**User feedback**: "c ben rendu large.. c etait parfait avant mais trop haut la c oknpas trop haut mais tout deceisse"
|
**What Needs Deployment**:
|
||||||
|
1. **Frontend** (`sociowire-frontend`)
|
||||||
|
- App.jsx - Added AppStore modal integration
|
||||||
|
- TopBarNew.jsx - Added App Store button (puzzle piece icon)
|
||||||
|
- PostCreateModal.jsx - Apps category already integrated
|
||||||
|
|
||||||
|
2. **Backend** (`apps-gateway`)
|
||||||
|
- Posts routes for app post creation
|
||||||
|
- S3 upload proxy
|
||||||
|
- Pulsar/webhook forwarding to external apps
|
||||||
|
|
||||||
Translation: "it's become wide.. it was perfect before but too high, now it's ok not too high but everything is displaced"
|
**Deployment Target**: Local Docker Swarm
|
||||||
|
|
||||||
### What's Working:
|
**Next Actions**:
|
||||||
- ✅ Height is now constrained (not going off top of screen)
|
1. Commit and push frontend changes to git
|
||||||
- ✅ Close button is accessible
|
2. Build and deploy frontend service
|
||||||
|
3. Build and deploy apps-gateway (if not already deployed)
|
||||||
|
4. Verify App Store button appears and works
|
||||||
|
## Active Session: Marketplace App Development (Jan 28 2026 - 19:12 UTC)
|
||||||
|
|
||||||
### What's Broken:
|
**Project**: `/home/swire/apps/marketplace-app` (standalone external app)
|
||||||
- ❌ Width is now too wide (was perfect before)
|
**Session ID**: 445206ee-6c75-4734-9c00-0a4b23dafde0
|
||||||
- ❌ "tout decisse" - everything is displaced/moved
|
|
||||||
|
|
||||||
### The Problem:
|
**Context**: This is the Marketplace example app for the external apps platform. It's a standalone project that:
|
||||||
In v0.0.133, I changed the width from `w-80` (320px) to `w-full` on mobile. The user wants the original width back.
|
- Runs independently from Sociowire codebase
|
||||||
|
- Connects to Sociowire via REST API (apps-gateway)
|
||||||
|
- Uses Fastify, SQLite with H3 geo-indexing, Pulsar
|
||||||
|
- Registers with Sociowire on startup
|
||||||
|
- Provides CRUD API for listings (posts)
|
||||||
|
- Responds to federated queries from Sociowire
|
||||||
|
|
||||||
### Fix Needed:
|
**Previous Status**: App was created and is functional. User is now working on this project.
|
||||||
Revert the width change on mobile:
|
|
||||||
- Keep `w-80` or `sm:w-80` (320px width)
|
|
||||||
- Keep the height fix `max-h-[65dvh]`
|
|
||||||
|
|
||||||
### Correct Changes for ChatWindowNew.jsx:
|
**Current Task**: TBD - waiting to see what user is doing.
|
||||||
```jsx
|
## External Apps Platform - Frontend Integration Complete (Jan 28 2026 - 19:14 UTC)
|
||||||
// Keep original width
|
|
||||||
className="w-80 sm:w-80 max-h-[65dvh]" // NOT w-full
|
|
||||||
|
|
||||||
// Messages area
|
**Status**: ✅ Frontend integration complete - ready to deploy
|
||||||
className="flex-1 min-h-0 overflow-y-auto" // No fixed height
|
|
||||||
|
**What Was Just Done**:
|
||||||
|
1. Added App Store button (puzzle piece icon) in TopBarNew
|
||||||
|
2. Integrated AppStore modal in App.jsx
|
||||||
|
3. PostCreateModal already has "Apps" category with app selection
|
||||||
|
|
||||||
|
**Complete User Flow**:
|
||||||
|
```
|
||||||
|
Click puzzle icon → App Store modal
|
||||||
|
↓
|
||||||
|
Browse apps by category (Marché, Services, Social, Info, Divertissement)
|
||||||
|
↓
|
||||||
|
Subscribe to apps (e.g., "Marketplace Montréal")
|
||||||
|
↓
|
||||||
|
Click + to create post
|
||||||
|
↓
|
||||||
|
Select "Apps" category
|
||||||
|
↓
|
||||||
|
Choose subscribed app from list
|
||||||
|
↓
|
||||||
|
Fill form (title, description, price, location, images)
|
||||||
|
↓
|
||||||
|
Post created via Sociowire → sent to external app
|
||||||
```
|
```
|
||||||
|
|
||||||
### Status:
|
**Files Modified**:
|
||||||
Height issue is RESOLVED ✅
|
- `/frontend-service/sociowire-frontend/src/components/Layout/TopBarNew.jsx` - Added App Store button
|
||||||
Width issue needs fixing - revert to original `w-80`
|
- `/frontend-service/sociowire-frontend/src/App.jsx` - Added AppStore modal integration
|
||||||
|
- `/frontend-service/sociowire-frontend/src/components/Posts/PostCreateModal.jsx` - Apps category already integrated
|
||||||
|
|
||||||
### Deployment:
|
**Current Task**: User wants to push everything and deploy to local Docker Swarm.
|
||||||
Will be v0.0.134 with correct width + height fix.
|
## External Apps Architecture - Implementation Progress (Jan 28 2026 - 17:50 UTC)
|
||||||
|
|
||||||
|
**Design Status**: ✅ COMPLETE
|
||||||
|
**Implementation Status**: 🔄 IN PROGRESS
|
||||||
|
|
||||||
|
**Architecture Summary**:
|
||||||
|
- **Federated content system** - Apps are data sources, Sociowire is aggregator/viewer
|
||||||
|
- **No local storage** - Posts fetched directly from apps when user is in zone
|
||||||
|
- **Zone-based fetching** - Queries apps for posts in geographic area (H3 sectors)
|
||||||
|
- **Preference matching** - Apps filter results based on user preferences
|
||||||
|
- **Federated search** - Search queries distributed to apps, results aggregated progressively via WebSocket
|
||||||
|
- **Real-time updates** - Pulsar for live changes
|
||||||
|
- **Global search integration** - Reco service queries both native posts AND subscribed apps, merges results
|
||||||
|
|
||||||
|
**APP EXECUTION MODEL - 2 LEVELS ONLY**:
|
||||||
|
|
||||||
|
**Level 1: JSON Config** (95% of apps)
|
||||||
|
- No code at all
|
||||||
|
- User defines card structure/layout in JSON via UI builder
|
||||||
|
- Can put car, form, or any content type on the map
|
||||||
|
- Sociowire renders based on JSON config
|
||||||
|
- Automatic validation
|
||||||
|
|
||||||
|
**Level 3: Sandboxed JS in Sociowire** (5% of apps)
|
||||||
|
- Code runs 100% inside Sociowire (NO iframe, NO external execution)
|
||||||
|
- Sandboxed JS interpreter (like QuickJS)
|
||||||
|
- Limited API whitelist (no fetch, no DOM access)
|
||||||
|
- Code submitted by app developer, validated, then executed in Sociowire
|
||||||
|
- Just data in → UI out transformation
|
||||||
|
|
||||||
|
**S3 ASSET PROXY DESIGNED**:
|
||||||
|
- **All assets go through Sociowire** - No direct S3 access from browser
|
||||||
|
- **Redis caching** - 1 hour TTL for resized images
|
||||||
|
- **Image resizing** - Using Sharp library
|
||||||
|
- **CDN headers** - Cache-Control: public, max-age=86400
|
||||||
|
- **URL transformation**: `s3://marketplace/img/phone.jpg` → `https://cdn.sociowire.com/apps/marketplace/img/phone.jpg?w=200&h=200`
|
||||||
|
- **Cache headers**: X-Cache: HIT/MISS
|
||||||
|
|
||||||
|
**Implementation Plan**:
|
||||||
|
1. ✅ Save design document → `docs/plans/2026-01-28-external-apps-design.md`
|
||||||
|
2. ✅ Create Marketplace example app → Standalone project that connects to apps-gateway
|
||||||
|
3. 🔄 Adapt apps-gateway → Add registration, webhook support, cache integration
|
||||||
|
4. 🔄 Design app subscription flow + consent UI
|
||||||
|
5. ✅ Design frontend app code execution model (2 levels: JSON config + sandboxed JS in Sociowire)
|
||||||
|
6. ✅ Design S3 cache proxy for app assets
|
||||||
|
7. 🔄 Implement S3 asset proxy service
|
||||||
|
8. 🔄 Implement sandboxed JS interpreter for Level 3 apps
|
||||||
|
9. ⏳ Frontend → App store UI, post creation via apps
|
||||||
|
|
||||||
|
**Marketplace App Created** (`/home/swire/sociowire-code/apps/marketplace-app/`):
|
||||||
|
- ✅ Fastify server with Pulsar integration
|
||||||
|
- ✅ SQLite database with H3 geo-indexing
|
||||||
|
- ✅ Registration flow with Sociowire on startup
|
||||||
|
- ✅ CRUD API for listings (posts)
|
||||||
|
- ✅ Search endpoint for federated queries
|
||||||
|
- ✅ Feed endpoint for zone-based map browsing
|
||||||
|
- ✅ Webhook handler for interactions
|
||||||
|
- ✅ Docker configuration
|
||||||
|
|
||||||
|
## External Apps Architecture - Implementation Complete ✅ (Jan 28 2026 - 17:50 UTC)
|
||||||
|
|
||||||
|
**Implementation Status**: ✅ COMPLETE - All files created and functional
|
||||||
|
|
||||||
|
**Architecture Summary**:
|
||||||
|
- **Federated content system** - Apps are data sources, Sociowire is aggregator/viewer
|
||||||
|
- **No local storage** - Posts fetched directly from apps when user is in zone
|
||||||
|
- **Zone-based fetching** - Queries apps for posts in geographic area (H3 sectors)
|
||||||
|
- **Preference matching** - Apps filter results based on user preferences
|
||||||
|
- **Federated search** - Search queries distributed to apps, results aggregated progressively via WebSocket
|
||||||
|
- **Real-time updates** - Pulsar for live changes
|
||||||
|
- **Global search integration** - Reco service queries both native posts AND subscribed apps, merges results
|
||||||
|
|
||||||
|
**APP EXECUTION MODEL - 2 LEVELS ONLY**:
|
||||||
|
|
||||||
|
**Level 1: JSON Config** (95% of apps)
|
||||||
|
- No code at all
|
||||||
|
- User defines card structure/layout in JSON via UI builder
|
||||||
|
- Can put car, form, or any content type on map
|
||||||
|
- Sociowire renders based on JSON config
|
||||||
|
- Automatic validation
|
||||||
|
|
||||||
|
**Level 3: Sandboxed JS in Sociowire** (5% of apps)
|
||||||
|
- Code runs 100% inside Sociowire (NO iframe, NO external execution)
|
||||||
|
- Sandboxed JS interpreter (like QuickJS)
|
||||||
|
- Limited API whitelist (no fetch, no DOM access)
|
||||||
|
- Code submitted by app developer, validated, then executed in Sociowire
|
||||||
|
- Just data in → UI out transformation
|
||||||
|
|
||||||
|
**S3 ASSET PROXY DESIGNED**:
|
||||||
|
- **All assets go through Sociowire** - No direct S3 access from browser
|
||||||
|
- **Redis caching** - 1 hour TTL for resized images
|
||||||
|
- **Image resizing** - Using Sharp library
|
||||||
|
- **CDN headers** - Cache-Control: public, max-age=86400
|
||||||
|
- **URL transformation**: `s3://marketplace/img/phone.jpg` → `https://cdn.sociowire.com/apps/marketplace/img/phone.jpg?w=200&h=200`
|
||||||
|
- **Cache headers**: X-Cache: HIT/MISS
|
||||||
|
|
||||||
|
**IMPLEMENTATION COMPLETE**:
|
||||||
|
|
||||||
|
**Backend (apps-gateway)**:
|
||||||
|
- ✅ `src/routes/registry.js` - App registration, listing, update, delete
|
||||||
|
- ✅ `src/routes/assets.js` - S3 asset proxy with Redis caching + Sharp resizing
|
||||||
|
- ✅ `src/routes/subscriptions.js` - User subscriptions with consent flow
|
||||||
|
- ✅ `src/routes/feed.js` - Federated feed queries to subscribed apps
|
||||||
|
- ✅ `src/sandbox.js` - QuickJS sandbox for Level 3 app code execution
|
||||||
|
- ✅ `src/redis.js` - Redis client initialization
|
||||||
|
- ✅ `src/server.js` - Updated to register all new routes
|
||||||
|
- ✅ `package.json` - Added dependencies (redis, sharp, quickjs-emscripten, nanoid, @aws-sdk/client-s3, @fastify/multipart)
|
||||||
|
- ✅ `Dockerfile` - Added vips-dev for Sharp image processing
|
||||||
|
|
||||||
|
**Frontend (sociowire-frontend)**:
|
||||||
|
- ✅ `src/components/Apps/AppStore.jsx` - Browse and subscribe to external apps
|
||||||
|
- ✅ `src/components/Apps/AppCard.jsx` - Display app in store
|
||||||
|
- ✅ `src/components/Apps/SubscribeModal.jsx` - Consent flow for subscriptions
|
||||||
|
- ✅ `src/components/Apps/ExtAppPostCard.jsx` - Render posts from external apps (Level 1 JSON + Level 3 pre-rendered)
|
||||||
|
- ✅ `src/components/Apps/MySubscriptions.jsx` - Manage user's subscriptions
|
||||||
|
- ✅ `src/components/Apps/useExtAppFeed.js` - Hook for fetching posts from subscribed apps
|
||||||
|
- ✅ `src/components/Apps/index.js` - Exports all components
|
||||||
|
- ✅ `src/api/extAppsApi.js` - API client for registry, subscriptions, feed, assets
|
||||||
|
|
||||||
|
**Marketplace Example App**:
|
||||||
|
- ✅ `apps/marketplace-app/` - Complete standalone app with Fastify, Pulsar, SQLite, H3 indexing
|
||||||
|
|
||||||
|
**Design Document**:
|
||||||
|
- ✅ `docs/plans/2026-01-28-external-apps-design.md` - Complete architecture documentation
|
||||||
|
|
||||||
|
**CRITICAL CORRECTIONS NEEDED**:
|
||||||
|
|
||||||
|
1. **External apps location**:
|
||||||
|
- User wanted apps in `/home/swire/apps/` (completely separate from sociowire-code)
|
||||||
|
- I created marketplace-app in `/home/swire/sociowire-code/apps/marketplace-app/` (wrong location)
|
||||||
|
- External apps should be independent projects, not part of sociowire codebase
|
||||||
|
- Need to move or recreate marketplace-app in `/home/swire/apps/`
|
||||||
|
|
||||||
|
2. **Post creation flow** (User said 100 times):
|
||||||
|
- **AUCUN accès direct à l'app** - User NE peut PAS contacter l'app directement
|
||||||
|
- **Tout passe par Sociowire** - Toutes les requêtes passent par Sociowire
|
||||||
|
- **Post creation flow**:
|
||||||
|
* User upload images → Sociowire S3 proxy (pas vers l'app)
|
||||||
|
* Sociowire stocke les images dans son S3
|
||||||
|
* Sociowire envoie le post à l'app avec les URLs des images
|
||||||
|
* L'app sauvegarde les URLs et ses propres métadonnées
|
||||||
|
* L'app possède son propre contenu, pas les images
|
||||||
|
- **User voit les apps enregistrées** quand il crée un post
|
||||||
|
- **Sociowire prend en charge de poster via l'app** (proxy)
|
||||||
|
|
||||||
|
**Deployment Steps Needed**:
|
||||||
|
1. Move marketplace-app to `/home/swire/apps/marketplace-app/` (separate from sociowire-code)
|
||||||
|
2. Rebuild apps-gateway with new dependencies (npm install, docker build)
|
||||||
|
3. Deploy updated apps-gateway to Docker Swarm
|
||||||
|
4. Add Redis secret to apps-gateway if not already present
|
||||||
|
5. Test complete flow: register app → subscribe → create post → view on map
|
||||||
|
|
||||||
|
**Deployment Steps Needed**:
|
||||||
|
1. Move marketplace-app to `/home/swire/apps/marketplace-app/` (separate from sociowire-code)
|
||||||
|
2. Rebuild apps-gateway with new dependencies (npm install, docker build)
|
||||||
|
3. Deploy updated apps-gateway to Docker Swarm
|
||||||
|
4. Add Redis secret to apps-gateway if not already present
|
||||||
|
5. Test complete flow: register app → subscribe → create post → view on map
|
||||||
|
|
||||||
|
|
||||||
|
## Chat Dialog Overflow - RESOLVED! ✅ (Jan 28 2026 - 06:00 UTC)
|
||||||
|
|
||||||
|
### ✅ Chat Window Mobile Height Issue - FIXED
|
||||||
|
|
||||||
|
**Final Solution** (v0.0.133):
|
||||||
|
- Added `max-h-[65dvh]` to chat window container on mobile
|
||||||
|
- Reverted width changes (kept original `w-80 sm:w-96`)
|
||||||
|
- Added keyboard detection to move window up when virtual keyboard opens
|
||||||
|
- Replaced `scrollIntoView()` with `scrollTop` to prevent parent scroll
|
||||||
|
|
||||||
|
**Status**: ✅ RESOLVED - User confirmed "parfait" (perfect)
|
||||||
|
|
||||||
|
### New Issue: Chat History Not Loading (Jan 28 2026 - 06:00 UTC)
|
||||||
|
|
||||||
|
**User feedback**: "l historique et le chat des fois passe pas. presentement lu aucun historiwue..."
|
||||||
|
|
||||||
|
**Problem**: Chat messages/history not loading for users onay01 and swadmin01
|
||||||
|
|
||||||
|
**Root Cause Found**: The `fetch()` calls in `useChat.js` were NOT sending authentication headers
|
||||||
|
|
||||||
|
The chat-service API requires Bearer token authentication, but the frontend was using `fetch()` directly without auth headers.
|
||||||
|
|
||||||
|
**Fix Applied** (v0.0.136):
|
||||||
|
```javascript
|
||||||
|
// Added import
|
||||||
|
import { loadAuth } from "../auth/authStorage";
|
||||||
|
|
||||||
|
// Helper function
|
||||||
|
function getAuthHeaders() {
|
||||||
|
try {
|
||||||
|
const auth = loadAuth();
|
||||||
|
const token = auth?.access_token;
|
||||||
|
if (!token) return {};
|
||||||
|
return { Authorization: `Bearer ${token}` };
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updated fetch calls
|
||||||
|
const res = await fetch(`${API_BASE}/messages?...`, {
|
||||||
|
headers: getAuthHeaders()
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Files Modified**:
|
||||||
|
- `/home/swire/sociowire-code/frontend-service/sociowire-frontend/src/components/Chat/useChat.js`
|
||||||
|
|
||||||
|
**Deployment**: v0.0.136 deployed with `--no-cache` and `--force`
|
||||||
|
|
||||||
|
### Performance Issue: Meilisearch Slowness (Jan 28 2026 - 06:00 UTC)
|
||||||
|
|
||||||
|
**User feedback**: Things are really slow sometimes, Meilisearch takes 4-5 seconds when not cached
|
||||||
|
|
||||||
|
**Analysis**:
|
||||||
|
- Direct Meilisearch access: 88ms (fast)
|
||||||
|
- Through discovery-service: 1.3s (slower)
|
||||||
|
- Difference is from data enrichment and database queries
|
||||||
|
- Redis caching already exists in discovery-service
|
||||||
|
|
||||||
|
**Potential Optimizations**:
|
||||||
|
1. More aggressive caching (longer TTL, cache more query patterns)
|
||||||
|
2. Reduce data enrichment (only enrich what's needed)
|
||||||
|
3. Pre-compute frequent search results
|
||||||
|
4. Add CDN for static assets
|
||||||
|
|
||||||
|
**Status**: Not blocking, user wants to test chat history fix first
|
||||||
|
|
||||||
|
### New Task: News Scraper Activity Check (Jan 28 2026 - 06:10 UTC)
|
||||||
|
|
||||||
|
**User request**: "j ai des news qui sont ajouter par un news scrapper.. tout au nom de tommy. peu tu checker quvil y en a eu bcp dernierement et que l enrichissement a bien marcher et donne moi les dernier enrichi..juste pour max 5hrs en arriere"
|
||||||
|
|
||||||
|
Translation: "I have news items being added by a news scraper... all under the name tommy. Can you check if there have been many added recently and if the enrichment worked well, and give me the recently enriched items... just for max 5 hours back"
|
||||||
|
|
||||||
|
**Task**:
|
||||||
|
1. Check how many news items were added recently (last 5 hours)
|
||||||
|
2. Verify enrichment worked correctly
|
||||||
|
3. Show recently enriched items
|
||||||
|
4. Focus on items added by "tommy" (author name)
|
||||||
|
|
||||||
|
**Likely services involved**:
|
||||||
|
- page-feeder (scrapes news)
|
||||||
|
- enrichment-worker (enriches news with metadata)
|
||||||
|
- discovery-service (stores enriched news)
|
||||||
|
- Meilisearch (indexes news for search)
|
||||||
|
|
||||||
|
### All Services Committed and Pushed:
|
||||||
|
- ✅ frontend-service: chat mobile fix + keyboard handling + auth fix
|
||||||
|
- ✅ sociowire-backend: SQL migrations passkeys
|
||||||
|
- ✅ discovery-service: meilisearch config
|
||||||
|
- ✅ search-service: update
|
||||||
|
- ✅ engagement-service: NATS handling
|
||||||
|
- ✅ page-feeder: meilisearch handling
|
||||||
|
- ✅ chat-service: session files
|
||||||
|
|
||||||
</guidance>
|
</guidance>
|
||||||
<pending_items description="Unfinished work, explicit TODOs, follow-up items mentioned across sessions. Clear items when resolved.">
|
<pending_items description="Unfinished work, explicit TODOs, follow-up items mentioned across sessions. Clear items when resolved.">
|
||||||
|
- Deploy external apps platform frontend (AppStore integration, Apps category in PostCreateModal)
|
||||||
|
- Deploy apps-gateway backend (post creation routes, S3 proxy)
|
||||||
|
- Test complete flow: subscribe to app → create post → view on map
|
||||||
- Migrate island-service and asset-service to NATS (currently use HTTP direct)
|
- Migrate island-service and asset-service to NATS (currently use HTTP direct)
|
||||||
- Fix chat-service - stopped working
|
- Fix chat-service - stopped working
|
||||||
- Git commit and push auth-service token refresh changes
|
- Git commit and push auth-service token refresh changes
|
||||||
|
|
@ -166,7 +456,88 @@ Login issue (Jan 28 2026): "session expired" error was caused by core-api and di
|
||||||
**Likely cause**: Services calling userinfo endpoint with tokens that don't include the `openid` scope. This is separate from the token refresh fix.
|
**Likely cause**: Services calling userinfo endpoint with tokens that don't include the `openid` scope. This is separate from the token refresh fix.
|
||||||
|
|
||||||
**Status**: Not blocking current testing. Monitor if this persists after token refresh verification.
|
**Status**: Not blocking current testing. Monitor if this persists after token refresh verification.
|
||||||
|
|
||||||
|
## External Apps Architecture (Jan 28 2026 - In Progress)
|
||||||
|
|
||||||
|
**User Request**: Create external apps system where users can code apps and integrate them via REST calls, possibly exposing Pulsar for larger clients.
|
||||||
|
|
||||||
|
**Architecture Goals**:
|
||||||
|
1. Users can code apps that display posts on maps
|
||||||
|
2. News posts refactored as external apps
|
||||||
|
3. Each app has:
|
||||||
|
- Pulsar channel for in/out
|
||||||
|
- S3-style address for assets
|
||||||
|
- Custom map style
|
||||||
|
- Code integration
|
||||||
|
4. Start with example app for selling articles
|
||||||
|
5. Connect to apps-gateway as external
|
||||||
|
|
||||||
|
**Key Requirements**:
|
||||||
|
- REST API integration for apps
|
||||||
|
- Pulsar messaging for high-volume clients
|
||||||
|
- External apps can display posts on maps
|
||||||
|
- News posts become external apps
|
||||||
|
- Each app has dedicated Pulsar topics (in/out)
|
||||||
|
- Asset storage via S3-compatible interface
|
||||||
|
- Custom map styling support
|
||||||
|
|
||||||
|
**Status**: Initial architecture phase - searching for existing infrastructure
|
||||||
</project_context>
|
</project_context>
|
||||||
|
<project_context_external_apps description="External Apps Platform architecture and implementation status">
|
||||||
|
## External Apps Architecture (Jan 28 2026 - Design Complete)
|
||||||
|
|
||||||
|
**User Request**: Create external apps system where users can code apps and integrate them via REST calls, with optional Pulsar messaging for high-volume clients.
|
||||||
|
|
||||||
|
**Architecture Goals**:
|
||||||
|
1. Users can code apps that display posts on maps
|
||||||
|
2. News posts refactored as external apps
|
||||||
|
3. Each app has:
|
||||||
|
- Pulsar channel for in/out
|
||||||
|
- S3-style address for assets
|
||||||
|
- Custom map style
|
||||||
|
- Code integration
|
||||||
|
4. Start with example app for selling articles
|
||||||
|
5. Connect to apps-gateway as external
|
||||||
|
|
||||||
|
**Key Requirements**:
|
||||||
|
- REST API integration for apps
|
||||||
|
- Pulsar messaging for high-volume clients
|
||||||
|
- External apps can display posts on maps
|
||||||
|
- News posts become external apps
|
||||||
|
- Each app has dedicated Pulsar topics (in/out)
|
||||||
|
- Asset storage via S3-compatible interface
|
||||||
|
- Custom map styling support
|
||||||
|
|
||||||
|
**Architecture - FEDERATED CONTENT SYSTEM**:
|
||||||
|
- Apps = data sources (own DB + assets)
|
||||||
|
- Sociowire = aggregator/viewer only
|
||||||
|
- NO local storage of app posts
|
||||||
|
- Zone-based fetching (H3 sectors) when user browses map
|
||||||
|
- Preference matching - apps filter results per user
|
||||||
|
- Federated search - queries distributed to apps, results aggregated progressively via WebSocket
|
||||||
|
- Real-time updates via Pulsar
|
||||||
|
- Global search - Reco service merges native posts + subscribed apps
|
||||||
|
|
||||||
|
**Design Decisions**:
|
||||||
|
- Monetization: Freemium simple (free to post, premium features later)
|
||||||
|
- Execution model: Hybrid (webhook for small clients, Pulsar direct for large)
|
||||||
|
- Search: Progressive loading via WebSocket
|
||||||
|
- Personalization: Apps control what each user sees (user context sent to providers)
|
||||||
|
|
||||||
|
**Broader Vision** (future):
|
||||||
|
- Eventually migrate ALL posts to federated model (news, friends posts, etc.)
|
||||||
|
- Everything distributed, nothing stored locally
|
||||||
|
- Current focus: External apps first, then expand to other content types
|
||||||
|
|
||||||
|
**Implementation Plan**:
|
||||||
|
1. Save design document → `docs/plans/2026-01-28-external-apps-design.md`
|
||||||
|
2. Create Marketplace example app → Standalone project that connects to apps-gateway
|
||||||
|
3. Adapt apps-gateway → Add registration, webhook support, cache integration
|
||||||
|
4. Frontend → App store UI, post creation via apps
|
||||||
|
|
||||||
|
**Status**: ✅ Design complete - ready for implementation
|
||||||
|
|
||||||
|
</project_context_external_apps>
|
||||||
<self_improvement description="Guidelines for evolving memory architecture and learning procedures.">
|
<self_improvement description="Guidelines for evolving memory architecture and learning procedures.">
|
||||||
MEMORY ARCHITECTURE EVOLUTION:
|
MEMORY ARCHITECTURE EVOLUTION:
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -8,12 +8,12 @@ import AppCard from "./AppCard";
|
||||||
import SubscribeModal from "./SubscribeModal";
|
import SubscribeModal from "./SubscribeModal";
|
||||||
|
|
||||||
const CATEGORIES = [
|
const CATEGORIES = [
|
||||||
{ id: "all", label: "Tout", icon: "fa-globe" },
|
{ id: "all", label: "All", icon: "fa-globe" },
|
||||||
{ id: "marketplace", label: "Marché", icon: "fa-store" },
|
{ id: "marketplace", label: "Marketplace", icon: "fa-store" },
|
||||||
{ id: "services", label: "Services", icon: "fa-wrench" },
|
{ id: "services", label: "Services", icon: "fa-wrench" },
|
||||||
{ id: "social", label: "Social", icon: "fa-users" },
|
{ id: "social", label: "Social", icon: "fa-users" },
|
||||||
{ id: "info", label: "Info", icon: "fa-info-circle" },
|
{ id: "info", label: "Info", icon: "fa-info-circle" },
|
||||||
{ id: "entertainment", label: "Divertissement", icon: "fa-gamepad" },
|
{ id: "entertainment", label: "Entertainment", icon: "fa-gamepad" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function AppStore({ onClose }) {
|
export default function AppStore({ onClose }) {
|
||||||
|
|
@ -30,19 +30,22 @@ export default function AppStore({ onClose }) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
const [appsResult, subsResult] = await Promise.all([
|
// Fetch apps (required) and subscriptions (optional - may fail if not logged in)
|
||||||
listApps({ category: category === "all" ? undefined : category }),
|
const appsResult = await listApps({ category: category === "all" ? undefined : category });
|
||||||
listSubscriptions(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
setApps(appsResult.apps || []);
|
setApps(appsResult.apps || []);
|
||||||
|
|
||||||
// Build subscriptions lookup
|
// Try to get subscriptions, but don't fail if unauthorized
|
||||||
const subsMap = {};
|
try {
|
||||||
for (const sub of subsResult.subscriptions || []) {
|
const subsResult = await listSubscriptions();
|
||||||
subsMap[sub.app_id] = sub;
|
const subsMap = {};
|
||||||
|
for (const sub of subsResult.subscriptions || []) {
|
||||||
|
subsMap[sub.app_id] = sub;
|
||||||
|
}
|
||||||
|
setSubscriptions(subsMap);
|
||||||
|
} catch (subErr) {
|
||||||
|
console.log("Could not load subscriptions (not logged in?):", subErr.message);
|
||||||
|
setSubscriptions({});
|
||||||
}
|
}
|
||||||
setSubscriptions(subsMap);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to load apps:", err);
|
console.error("Failed to load apps:", err);
|
||||||
setError(err.message);
|
setError(err.message);
|
||||||
|
|
@ -75,7 +78,7 @@ export default function AppStore({ onClose }) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
<div className="fixed inset-0 bg-black/80 backdrop-blur-sm z-[1100] flex items-center justify-center p-4">
|
||||||
<div className="bg-zinc-900 rounded-2xl w-full max-w-4xl max-h-[90vh] overflow-hidden flex flex-col">
|
<div className="bg-zinc-900 rounded-2xl w-full max-w-4xl max-h-[90vh] overflow-hidden flex flex-col">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between p-4 border-b border-zinc-800">
|
<div className="flex items-center justify-between p-4 border-b border-zinc-800">
|
||||||
|
|
@ -123,13 +126,13 @@ export default function AppStore({ onClose }) {
|
||||||
onClick={loadApps}
|
onClick={loadApps}
|
||||||
className="mt-4 px-4 py-2 bg-zinc-800 rounded-lg hover:bg-zinc-700"
|
className="mt-4 px-4 py-2 bg-zinc-800 rounded-lg hover:bg-zinc-700"
|
||||||
>
|
>
|
||||||
Réessayer
|
Retry
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : apps.length === 0 ? (
|
) : apps.length === 0 ? (
|
||||||
<div className="text-center text-zinc-500 py-8">
|
<div className="text-center text-zinc-500 py-8">
|
||||||
<i className="fas fa-box-open text-4xl mb-4" />
|
<i className="fas fa-box-open text-4xl mb-4" />
|
||||||
<p>Aucune app disponible dans cette catégorie</p>
|
<p>No apps available in this category</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,18 @@ import {
|
||||||
decryptMessage,
|
decryptMessage,
|
||||||
isE2EAvailable,
|
isE2EAvailable,
|
||||||
} from "./cryptoUtils";
|
} from "./cryptoUtils";
|
||||||
|
import { loadAuth } from "../../auth/authStorage";
|
||||||
|
|
||||||
|
function getAuthHeaders() {
|
||||||
|
try {
|
||||||
|
const auth = loadAuth();
|
||||||
|
const token = auth?.access_token;
|
||||||
|
if (!token) return {};
|
||||||
|
return { Authorization: `Bearer ${token}` };
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const WS_BASE = import.meta.env.VITE_CHAT_WS_URL ||
|
const WS_BASE = import.meta.env.VITE_CHAT_WS_URL ||
|
||||||
(window.location.protocol === "https:" ? "wss://" : "ws://") +
|
(window.location.protocol === "https:" ? "wss://" : "ws://") +
|
||||||
|
|
@ -277,7 +289,10 @@ export function useChat({ username, enabled = true, onNewMessage }) {
|
||||||
if (!username || !otherUsername) return [];
|
if (!username || !otherUsername) return [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API_BASE}/messages?username=${encodeURIComponent(username)}&other=${encodeURIComponent(otherUsername)}`);
|
const res = await fetch(`${API_BASE}/messages?other=${encodeURIComponent(otherUsername)}`, {
|
||||||
|
headers: getAuthHeaders(),
|
||||||
|
credentials: "include",
|
||||||
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
if (data.ok && data.messages) {
|
if (data.ok && data.messages) {
|
||||||
|
|
@ -295,7 +310,10 @@ export function useChat({ username, enabled = true, onNewMessage }) {
|
||||||
if (!username) return [];
|
if (!username) return [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API_BASE}/conversations?username=${encodeURIComponent(username)}`);
|
const res = await fetch(`${API_BASE}/conversations`, {
|
||||||
|
headers: getAuthHeaders(),
|
||||||
|
credentials: "include",
|
||||||
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
if (data.ok && data.conversations) {
|
if (data.ok && data.conversations) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue