Choosing between local and server data
Going with your existing code, the promise part can be simplified.

var getStuff = function(){
  return !!$localStorage.stuff ? $q.resolve({ data: $localStorage.stuff })
                               : $http.get('data/sample.json').then(function(response){
                                   $localStorage.stuff = response;
                                   return response;
                                 });
};


You appear to check against undefined and a blank string for stuff, both falsy values. We can simplify by coercing them to a boolean using !!. Another improvement is using $q.resolve, which returns an already resolved promise, resolved value optional. In the same way, $http.get also returns a promise. We can simply just return them instead of creating a new promise wrapper.

myappservice.getStuff().then(function(result){
  $scope.test = result.data[950].Id;
  console.log("returned");
});


We can also chain the then to getStuff since getStuff returns a promise. Much easier to follow chained stuff than breaking them apart (might be personal preference, but chaining makes code appear like sentences instead of commands).

As for a pattern, I think this one is fine since this is a one-off request (call and get) and the controller has been shielded from knowing where the data came from.

However, if you decide to go stream this data in, like say from a websocket, or make your service poll for changes, or react to localStorage events, then the suggested Observer Pattern might be your best bet. Make your service collect callbacks and fire them when something interesting happens.