#ifndef STORE_H #define STORE_H #include "models.h" #include #include QT_BEGIN_NAMESPACE class QJsonDocument; class QNetworkReply; QT_END_NAMESPACE /// Represents an in-flight API operation. /// Wraps a QNetworkReply: owns cleanup, parses JSON, and emits signals. /// Automatically deletes itself after finished() fires. class Operation : public QObject { Q_OBJECT public: explicit Operation(QNetworkReply *reply, QObject *parent = nullptr); signals: void success(const QJsonDocument &response); void failed(const QString &message); void finished(); }; /// Central data store backed by the Orion API. /// Holds cached state and exposes read-only accessors + mutating operations. class Store : public QObject { Q_OBJECT public: explicit Store(QObject *parent = nullptr); // ── Read-only accessors ── const QList &networks() const; int networkCount() const; const Network *networkById(const QString &id) const; QList streamsForNetwork(const QString &networkId) const; int streamCount(const QString &networkId) const; const Stream *streamById(const QString &id) const; const QList &particlesForStream(const QString &streamId) const; int particleCount(const QString &streamId) const; const Particle *particleById(const QString &id) const; // ── Bootstrap ── Operation *loadStartupData(); // ── Network operations ── Operation *createNetwork(const QString &name); Operation *fetchNetworks(); Operation *fetchNetwork(const QString &networkId); Operation *addNetworkMembers(const QString &networkId, const QStringList &emails); Operation *removeNetworkMember(const QString &networkId, const QString &email); Operation *setStreamCapacity(const QString &networkId, int capacity); // ── Stream operations ── Operation *createStream(const QString &networkId, const QString &name, const QString &description, const QString &visibility = "network_all", const QStringList &members = {}); Operation *fetchStream(const QString &streamId); Operation *updateStream(const QString &streamId, const QString &name, const QString &description); Operation *openStream(const QString &streamId); Operation *closeStream(const QString &streamId); Operation *addStreamMembers(const QString &streamId, const QStringList &emails); Operation *removeStreamMembers(const QString &streamId, const QStringList &emails); // ── Particle operations ── Operation *createParticle(const QString &streamId, const QString &type, const QMap &data); Operation *fetchParticle(const QString &particleId); Operation *updateParticle(const QString &particleId, const QMap &data); Operation *deleteParticle(const QString &particleId); Operation *markParticleSeen(const QString &particleId); Operation *markParticlesSeen(const QStringList &particleIds); Operation *ackParticle(const QString &particleId); void setCurrentUserEmail(const QString &email); QString currentUserEmail() const; signals: // ── Data-change signals ── void networksChanged(); void streamsChanged(const QString &networkId); void particlesChanged(const QString &streamId); // Granular signals for in-place property updates (no structural change) void particleUpdated(const QString &streamId, const QString &particleId); void streamUpdated(const QString &streamId); void startupDataLoaded(); void errorOccurred(const QString &message); private: // ── Internal state ── QList m_networks; QMap> m_particles; // streamId -> particles QMap m_networkIndex; // networkId -> index in m_networks QMap m_streamToNetwork; // streamId -> networkId QString m_currentUserEmail; // ── JSON parsing ── static Human parseHuman(const QJsonObject &obj); static Network parseNetwork(const QJsonObject &obj); static Stream parseStream(const QJsonObject &obj); static Particle parseParticle(const QJsonObject &obj); void populateFromStartupData(const QJsonObject &root); // ── State mutation helpers ── void upsertNetwork(const Network &network); void upsertStream(const QString &networkId, const Stream &stream); void upsertParticle(const QString &streamId, const Particle &particle); void removeParticleFromState(const QString &particleId); /// Returns the streamId that contains the given particle, or empty QString. QString findStreamForParticle(const QString &particleId) const; }; #endif // STORE_H